当前位置: 首页 > news >正文

React进阶:React Hooks的使命是分离规整,不是杂糅

如果你刚接触React Hooks,你可能会觉得学了很多useXxx() API但还是写不出好代码。

原因很简单:网上大多数教程都在教你怎么调用一个Hook,而不是教你在真实场景中应该用哪个、为什么用它。

本文直接用真实场景说话。


一、useState vs useReducer:不是复杂度的区别

你可能看过这种说法:“简单状态用useState,复杂状态用useReducer”。

这个建议害了很多人。实际上,判断标准不是"复杂度",而是"逻辑关联性"

什么时候用useState

const[count,setCount]=useState(0)const[name,setName]=useState('')const[isOpen,setIsOpen]=useState(false)

这些状态之间互不依赖,每个独立变化。用useState足够。

什么时候用useReducer

// 表单状态:多个字段需要同时更新const[form,dispatch]=useReducer(formReducer,{name:'',email:'',phone:'',address:'',errors:{}})functionformReducer(state,action){switch(action.type){case'SET_FIELD':return{...state,[action.field]:action.value}case'SET_ERRORS':return{...state,errors:action.errors}case'RESET':returninitialStatedefault:returnstate}}

判断标准很简单:如果更新一个状态时需要同时知道其他状态的值,就用useReducer。


二、useEffect:80%的人用错了依赖数组

useEffect是React Hooks里最容易出错的地方。

规则1:依赖数组应该包含所有你用到的东西

// ❌ 错误:用了count但没在依赖里声明useEffect(()=>{document.title=`点击了${count}`},[])// ✅ 正确useEffect(()=>{document.title=`点击了${count}`},[count])

规则2:不要在useEffect里更新它依赖的值(除非有条件)

// ❌ 无限循环useEffect(()=>{setCount(count+1)},[count])// ✅ 有条件useEffect(()=>{if(count<10){setCount(count+1)}},[count])

规则3:数据请求应该在useEffect里做,但要避免竞态

useEffect(()=>{letcancelled=falsefetch(`/api/user/${userId}`).then(res=>res.json()).then(data=>{if(!cancelled){setUser(data)}})return()=>{cancelled=true// 组件卸载或userId变化时取消旧请求}},[userId])

三、自定义Hook:把逻辑从组件中抽出来

这是Hooks最大的价值所在,也是大多数人没有充分利用的功能。

不好的写法:逻辑和UI混在一起

functionUserList(){const[users,setUsers]=useState([])const[loading,setLoading]=useState(true)const[error,setError]=useState(null)useEffect(()=>{fetch('/api/users').then(res=>res.json()).then(data=>{setUsers(data)setLoading(false)}).catch(err=>{setError(err.message)setLoading(false)})},[])if(loading)return<div>加载中...</div>if(error)return<div>错误:{error}</div>return(<ul>{users.map(u=><li key={u.id}>{u.name}</li>)}</ul>)}

好的写法:逻辑抽成自定义Hook

functionuseUsers(){const[users,setUsers]=useState([])const[loading,setLoading]=useState(true)const[error,setError]=useState(null)useEffect(()=>{fetch('/api/users').then(res=>res.json()).then(data=>{setUsers(data)setLoading(false)}).catch(err=>{setError(err.message)setLoading(false)})},[])return{users,loading,error}}functionUserList(){const{users,loading,error}=useUsers()if(loading)return<div>加载中...</div>if(error)return<div>错误:{error}</div>return(<ul>{users.map(u=><li key={u.id}>{u.name}</li>)}</ul>)}

抽出来之后,useUsers可以在任何组件中复用,测试也更方便。

常用自定义Hook示例

// 监听窗口大小functionuseWindowSize(){const[size,setSize]=useState({width:window.innerWidth,height:window.innerHeight})useEffect(()=>{consthandle=()=>setSize({width:window.innerWidth,height:window.innerHeight})window.addEventListener('resize',handle)return()=>window.removeEventListener('resize',handle)},[])returnsize}// 本地存储functionuseLocalStorage(key,initialValue){const[value,setValue]=useState(()=>{conststored=localStorage.getItem(key)returnstored?JSON.parse(stored):initialValue})useEffect(()=>{localStorage.setItem(key,JSON.stringify(value))},[key,value])return[value,setValue]}

四、useMemo和useCallback:不要过早优化

大部分人用这两个Hook的时机是错的。

什么时候真的需要用

// ❌ 不需要:计算很简单constdoubled=useMemo(()=>count*2,[count])// ✅ 需要:计算代价很大constsortedUsers=useMemo(()=>{returnusers.sort((a,b)=>expensiveCompare(a,b))},[users])

黄金法则:先不用useMemo和useCallback,等真的出现性能问题(在React DevTools Profiler里能测出来)再添加。


五、常见模式和反模式

不要写复杂的useEffect

// ❌ 反模式:一个useEffect做太多事useEffect(()=>{fetchUser()fetchPosts()setupWebSocket()trackPageView()},[userId])
// ✅ 拆成多个useEffect(()=>{fetchUser()},[userId])useEffect(()=>{fetchPosts()},[userId])useEffect(()=>{setupWebSocket();returncleanup},[userId])useEffect(()=>{trackPageView()},[])

每个useEffect只做一件事。

不要滥用状态

// ❌ 可以从已有数据计算出来的就不要存const[firstName,setFirstName]=useState('')const[lastName,setLastName]=useState('')const[fullName,setFullName]=useState('')// ✅ 直接用constfullName=firstName+' '+lastName

六、迁移建议:从Class到Hooks

如果你的项目还在用Class组件,这是一个安全的迁移路径:

  1. 新组件全部用Hooks
  2. 旧组件不急着改,遇到bug或新需求时再改
  3. 优先把"逻辑密集型"的Class组件改成Hooks(因为自定义Hook可以显著降低复杂度)

结语

Hooks不仅仅是另一种写法,它是一种更自然的"把UI和逻辑分离开"的思路。

掌握Hooks的关键不是背API,而是学会在工作中识别:“这段逻辑能抽出来用自定义Hook吗?”

多写、多拆、多复用,自然就熟练了。

http://www.cnnetsun.cn/news/3101358.html

相关文章:

  • 2026大厂薪资揭秘:AI涨薪翻倍,传统岗位或被冻结!速收藏,助你跳槽选Offer!
  • 网络设备ECMP负载均衡工作原理
  • 小爱音箱音乐播放终极指南:免费解锁无限听歌体验
  • WebView 与 H5 加速
  • 《墨香情》2026年7月最新官网下载:正统复刻水墨江湖
  • 智能安全测试实战:从AI原理到Strix AI工具应用指南
  • 提示词工程实战:让 AI 输出精准结果的 20 个核心技巧
  • Wireshark与iptables组合实战:网络协议分析与防火墙绕过技术深度解析
  • 多云互联一定要用云专线吗?SD-WAN跨云组网成本直降50%的三种玩法
  • WeMod增强工具终极指南:如何通过开源技术解锁完整游戏体验
  • HsMod终极指南:炉石传说55项功能优化插件完整教程
  • RFID智能仓储管理系统厂家有哪些?八家核心品牌分享
  • 思源宋体终极指南:7种粗细的免费开源中文字体完整教程
  • 思源宋体免费开源字体:7种粗细的完整使用指南
  • 2026年高效吸塑包装加工,认准正规优质工具厂家
  • VMware虚拟机自启动配置的“隐形开关”:92%工程师忽略的/etc/vmware/hostd/config.xml中startupPolicy参数深度解析
  • 从SEO到AEO:企业增长生态的技术重构
  • RS232 保护电路TVS 管的选择
  • VMware虚拟化双雄对决:Workstation vs ESXi——从开发测试到生产部署的7个决策红线(运维总监亲授)
  • 3分钟将手机变身高清摄像头:DroidCam OBS插件终极指南
  • 【紧急修复通道】:vmrun批量操作中断/超时/权限拒绝?立即生效的4行诊断命令+6种根因速判法(附实时日志解析工具链)
  • 【VMware黑屏零容忍方案】:强制启用VGA模式+禁用3D加速+重置vmx配置——3行命令秒级恢复
  • Selenium自动化实战:从登录到下单的完整流程与避坑指南
  • VMware无法识别CPU虚拟化?不是BIOS问题!Hyper-V遗留hvboot.sys与vmx模块加载时序冲突实录(附Wireshark级日志取证)
  • 如何在Blender中快速实现专业级3MF格式支持:终极免费插件指南
  • 空洞骑士模组管理新体验:Scarab模组管理器完全指南
  • GitHub终极加速指南:如何让下载速度飙升10倍以上
  • 仅限内部流传的macOS虚拟机启动密钥包:含定制Unlocker 4.4.1+自动脚本+Apple认证绕过方案(限时开放)
  • Hyper-V启用后VMware Player黑屏?GPU直通失效?独家发现Windows 11 23H2内核补丁KB5034441引发的HVCI兼容断层
  • 实体生意抖音获客起号指南,让你持续获客