尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

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

React进阶:React Hooks的使命是分离规整,不是杂糅
📅 发布时间:2026/7/2 10:17:37

如果你刚接触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吗?”

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

相关新闻

  • AEUX开源架构解析:实现Figma与After Effects无缝工作流的技术方案
  • 大数据中的各种场景数据倾斜的介绍
  • 工业4-20mA电流环与DAC161S997高精度驱动方案

最新新闻

  • Java开发必备工具链:从IDE到持续集成
  • Vue与Java前后端国密SM4加解密统一方案实践
  • 软考案例分析速成闭环(1套框架+4类题型+6种陷阱识别法)——限200份内部训练手册同步放送
  • 基于Si4731与PIC18F87K22的数字收音机系统设计与实现
  • 如何快速实现九大网盘高速下载:LinkSwift完整技术指南
  • 家用豆浆机选购参考 豆浆机排行榜前十名有哪些款式

日新闻

  • Python Playwright录制功能:从零到一构建自动化测试脚本
  • 如何用开源工具永久保存你心爱的小说:novel-downloader全攻略
  • In-Context Learning不是教知识,而是模式对齐:从5个示例到100个工业级样本的真相

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号