react-hooks 一般写法汇总

news/2024/11/22 20:25:23/

文件一般写法

// 引入统一封装api请求
import { getById } from "@/api";
// 引入ui组件库
import { Toast } from "antd-mobile";
// useEffect 类似vue中watch,或者moundted生命周期,视第二参数数据而定
// useState 是vue2的data、是vue3的ref或reactive,总之是动态绑定数据,用于视图使用
// useMemo 用于防止子组件随父组件变动而实时刷新,尤其是无畏刷新
import { useEffect, useState, useMemo } from "react";
// useSearchParams,查找路由后面?跟的数据
// useLocation,获取路由pathname
import { useSearchParams, useLocation } from "react-router-dom";
// 引入样式,如果以module方式命名,类似于vue中的scss scoped
import Styles from './index.module.less'
import '@/layout/navbar/index.less'
// 自用组件引入
import PvForm from "@/components/PvForm";
// searchRoute搜索路由总体参数(包含meta等)
import {searchRoute} from "@/router/utils/guard.jsx";
// rootRouter函数式路由 汇总
import {rootRouter} from "@/router/index.jsx";
const Station = (props) => {// 获取路由名const { pathname } = useLocation()const route = searchRoute(pathname, rootRouter)// * 获取自定义的路由配置const { nav } = route.meta// 记录当前滚动条距离const [scrollTop, setScrollTop] = useState(0);// 使用路由后? 跟随的参数const [searchParams, setSearchParams] = useSearchParams();// 传递组件参数 初始化	const [ tdInfo, setTdInfo] = useState({title: '土地资质',list: [{ name: 'projectReportImage',label: '项目可研报告', type: 'text', value: '', },],})// api接口获取信息处理const getDetail = (params, routeParams = { mode: 'YX'}) => {// 获取信息getById(params).then(res => {const { success, result, error} = resif (success) {judgeBuild(result); // 存储信息 } else {Toast.show({content: error || '信息获取失败'});}})}// 判断是否存在const judgeBuild = (res) => {const { projectType } = resconst isTdInfo = tabList.some(item => item.label === 'tdInfo')// 特定性逻辑处理if (['PUB_BUILD'].includes(projectType) && !isTdInfo) {const index = tabList.findIndex(item => item.label === 'information')tabList.splice(index+1, 0, {name: '资质',label: 'tdInfo'})setTabList(tabList)// 设置信息const { list } = tdInfoconst { stationCode } = resconst projectReportImage = res.projectReportImage ? `报告-${stationCode}` : '无'const landImage = res.landImage ? `性质-${stationCode}` : '无'const landContractImage = res.landContractImage ? `公示-${stationCode}` : '无'const noImpactImage = res.noImpactImage ? `证明-${stationCode}` : '无'const loadReportImage = res.loadReportImage ? `报告-${stationCode}` : '无'Object.assign(commObj, { projectReportImage, landImage, landContractImage, noImpactImage, loadReportImage })list.forEach(item => {item.value = commObj[item.name]})setTdInfo({...projectInfo, list})}}// 监听函数const handleScroll = (e) => {// 监听div内滚动条距离顶部距离if(e && e.target.scrollTop) {setScrollTop(e.target.scrollTop)}}// * 渲染后加载 useEffectuseEffect(() => {// 作接口请求const { stationId } = propsconst routeParams = searchParams.get("mode");getDetail({stationId},routeParams)// 监听滚动事件window.addEventListener("scroll", handleScroll, true);handleScroll()// 销毁滚动监听事件 return中的执行 (同 vue2 beforeDestroy、vue3 onBeforeUnmount)return () => window.removeEventListener("scroll", handleScroll, false);}, []); // useEffect 第二参数,确定其重复次数 为空数组时,仅执行一次(同 vue2 mounted vue3 onMounted)// 若无参数,则每次重绘都会执行(同 vue2 updated、vue3 onUpdated),若有参数则,参数变化才会变(同vue的watch监听)
// 使用useMemo 对子组件进行防止无用更新处理。第二个参数 是参数变换 才进行重新渲染标志
const projectInfoDom = useMemo(() => <PvForm tdInfo={tdInfo}/>, [tdInfo]);return (<><div className={`${Styles.content} w-full`}>{scrollTop < 15 && <div className={`${Styles.head} w-full navbar ${nav}`}></div>}<div className={`${Styles.bottom}`} style={{padding: '0 12px'}}>{projectInfoDom}<div style={{marginTop: '10px'}}>{projectInfoDom}</div></div></div></>)
}export default Station
.navbar {border-bottom: 0;
}
.content {background: #F7F8FA;min-height: calc(100vh - 45px);padding-bottom: 48px;.head {height: 36px;position: absolute;top: 40px;border-bottom: 0;}.bottom {position: relative;z-index: 1;}
}

组件一般写法

import { useEffect, useState } from "react";
import PvImageViewer from "@/components/PvForm/PvImageViewer"
import PvConfTable from "@/components/PvForm/PvConfTable"
import PvTimeLine from "@/components/PvForm/PvTimeLine"
import "./index.less"
import noData from "@/assets/img/noData.png"const PvForm = (props) => {// console.log('pvForm', props)const [ tab, setTab ] = useState({index: 0,prop: props?.default || props?.prop // 适配tab项,如果没有tab 默认获取prop展示})const chooseTab = (index, item) => {setTab({index, prop: props[item.label] || {list:[]} })props.communication(index, item)}const isEmpty = (a) => {if (['', null, undefined].includes(a)) return true        if (Array.prototype.isPrototypeOf(a) && a.length === 0 ) return true; //检验空数组if (Object.prototype.isPrototypeOf(a) && Object.keys(a).length === 0 ) return true;  //检验空对象return false;}return (<><div className="content w-full">{ props.tabList && props.tabList.length && <div className='tab-list flex'>{props.tabList.map((item, index) => {return <div className={`tab-item ${tab.index === index ? 'tab-item-active' : ''}`} key={item.name} onClick={() => chooseTab(index, item)}>{item.name}</div>})}</div>}{tab.prop.title && <div className="title">{tab.prop.title}</div>}{tab.prop.list && tab.prop.list.every(item => isEmpty(item.value)) && <div className="flex flex-col items-center w-full"><img style={{width: '200px', height: '200px'}} src={noData}/><div style={{color: "#999999"}}>暂无信息</div></div>}<div className="items">{tab.prop.list.map((item, index) => {if (!isEmpty(item.value)) {if (['text'].includes(item.type)) {return <div className="form-item flex" key={item.name}><div className='item-label'>{item.label}</div><div className="item-value">{item.value}</div><div className="item-unit">{item.unit}</div></div>}if (['upload'].includes(item.type)) {return <div className="form-item" key={item.name}><div className='item-label'>{item.label}</div><div className="item-value"><PvImageViewer list={item.value}></PvImageViewer></div><div className="item-bottom-line"></div></div>}if (['uploads'].includes(item.type)) {return item.value.map(it => {return <div className="form-item" key={it.name}><div className='item-label'>{it.label}</div><div className="item-value"><PvImageViewer list={it.value}></PvImageViewer></div></div>})}if (['table'].includes(item.type)) {return <div key={index}>{item.label && <div className="title">{ item.label }</div>}{item.value.map((it, ind) => {return <PvConfTable list={it} key={ind}/>})}</div>}if (['timeline'].includes(item.type)) {return <div key={index}>{item.label && <div className="title">{ item.label }</div>}<PvTimeLine list={item.value}></PvTimeLine></div>}}})}</div></div></>)
}export default PvForm
.content {background: #ffffff;border-radius: 8px;padding: 16px 0 20px 0;// font-size: var(--adm-font-size-7);.tab-list {margin: 17px 15px 16px 15px;.tab-item {flex: 1;height: 32px;line-height: 32px;background: #2283e21a;font-size: 12px;color: #2283E2;border: 1px solid #2283e21a;text-align: center;&:nth-child(1) {border-radius: 4px 0px 0px 4px;}&:nth-last-child(1) {border-radius: 0px 4px 4px 0px;}}.tab-item-active {background: #2283E2;border: 1px solid #2283E2;color: #ffffff;}}.title {font-size: 14px;font-weight: bold;color: #323233;padding: 0 0 12px 0;margin: 0 15px 0 15px;border-bottom: 1px solid #EBEDF0;&:nth-child(n+2) {margin-top: 16px;}}.form-item {margin-top: 12px;padding: 0 15px;font-size: 14px;color: #C8C9CC;.item-label {width: 90px;}.item-bottom-line {margin-top: 12px;height: 1px;background: #EBEDF0;}.item-value {color: #323233;flex: 1;}}
}

图片preview 组件 写法示例

import { useEffect, useState } from "react";
import { ImageViewer } from "antd-mobile";
import "./index.less"const PvImageViewer = (props) => {const [visible, setVisible] = useState(false)const [imageSrc, setImageSrc] = useState(null)const imageView = (src) => {setImageSrc(src)setVisible(true)}return (<><div className="image-view flex flex-wrap items-baseline">{props.list &&props.list.length &&props.list.map((item, index) => {return <div className="image-item flex flex-col align-center justify-center" style={{width: '30%'}} onClick={ () => imageView(item.imgSrc) } key={index}><img className="w-full" style={{ objectFit: 'cover', height: '26vw' }} src={item.imgSrc + '?x-oss-process=image/resize,m_lfit,h_200,w_200'} alt="" /><div className="image-name">{item.imgName}</div></div>})}<ImageViewerimage={imageSrc}visible={visible}onClose={() => {setVisible(false)}}/></div></>)
}export default PvImageViewer
.image-view {.image-item {margin-top: 8px;&:nth-child(3n+2) {margin-left: 15px;}&:nth-child(3n+3) {margin-left: 15px;}.image-name {font-size: 10px;margin-top: 6px;color: #969799;text-align: center;display: block;}}
}

http://www.ppmy.cn/news/1054301.html

相关文章

创建型(二) - 单例模式

一、概念 单例设计模式&#xff08;Singleton Design Pattern&#xff09;&#xff1a;一个类只允许创建一个对象&#xff08;或者实例&#xff09;&#xff0c;那这个类就是一个单例类。 优点&#xff1a;在内存里只有一个实例&#xff0c;减少了内存的开销&#xff0c;避免…

中国移动秋招攻略,网申测评和面试

中国移动秋招简介 按照往年的惯例来看&#xff0c;移动会在每年的8月份发布相关秋招信息&#xff0c;紧接着考生并进行网申&#xff0c;面试的时间跨度也非常的长&#xff0c;大概是9~12月份。整个招聘流程&#xff0c;包括投递简历网申&#xff0c;笔试测评&#xff0c;面试录…

Cyanine3 NHS ester生物分子的标记与共价结合1032678-38-8

​欢迎来到星戈瑞荧光stargraydye&#xff01;小编带您盘点&#xff1a; Cyanine3 NHS ester是一种荧光染料&#xff0c;可用于将含有游离氨基&#xff08;-NH2&#xff09;的生物分子如蛋白质、抗体、肽段、核酸等进行标记和共价结合。这个过程通常称为NHS酯化反应&#xff0c…

使用Matlab coder 生成函数‘referencePathFrenet’ 对应C/C++代码含有超大数组

嵌入式需要使用C/C集成&#xff0c;开发使用Matlab&#xff0c;然后使用 coder 生成函数‘referencePathFrenet’ 生成了对应的C/C代码&#xff0c;然而C代码含有大量超大数组导致嵌入式无法集成&#xff1a; 分析Matlab 源代码发现是dclothoid.m 里面路径插值的时候默认使用了…

solidity0.8.0的应用案例9:代理合约

代码由OpenZeppelin的Proxy合约简化而来。 代理模式 Solidity合约部署在链上之后,代码是不可变的(immutable)。这样既有优点,也有缺点: 优点:安全,用户知道会发生什么(大部分时候)。坏处:就算合约中存在bug,也不能修改或升级,只能部署新合约。但是新合约的地址与…

野狼测评工作室:电视机顶盒哪个牌子好?电视机顶盒排行榜

欢迎各位来到野狼测评&#xff0c;本期工作室的测评产品是电视机顶盒&#xff0c;电视机顶盒不仅可以让老电视变得智能化&#xff0c;也可以让配置落后的智能电视在不换新的前提下升级配置&#xff0c;本周我们测评了十几款热门电视机顶盒&#xff0c;盘点电视机顶盒排行榜&…

区块链-Web3.0-什么是Web3.0?

一、什么是Web 3.0 Web 3.0&#xff0c;也被称为“去中心化Web”或“智能Web”&#xff0c;是互联网的下一代&#xff0c;它使用了分布式系统技术、区块链技术和智能合约等新型技术&#xff0c;旨在构建一个更加去中心化、安全、透明和智能的互联网。Web 3.0 可以带来更广泛的…

微服务框架之SpringBoot面试题汇总

微服务框架之SpringBoot面试题汇总 什么是Spring Boot&#xff1f; 多年来&#xff0c;随着新功能的增加&#xff0c;spring变得越来越复杂。Spring项目&#xff0c;我们必须添加构建路径或添加Maven依赖关系&#xff0c;配置应用程序服务器&#xff0c;添加spring配置。因此&…