news 2026/7/2 10:16:42

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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吗?”

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 10:14:10

网络设备ECMP负载均衡工作原理

网络设备ECMP负载均衡工作原理 原创 网络老技工 博主文章分类&#xff1a;网络设计和运维 文章标签 负载均衡 ECMP HASH HASH极化 文章分类 负载均衡 服务器 阅读数4**** ©著作权归作者所有&#xff1a;来自51CTO博客作者网络老技工的原创作品&#xff0c;请联系作者获…

作者头像 李华
网站建设 2026/7/2 10:12:44

小爱音箱音乐播放终极指南:免费解锁无限听歌体验

小爱音箱音乐播放终极指南&#xff1a;免费解锁无限听歌体验 【免费下载链接】xiaomusic 使用小爱音箱播放音乐&#xff0c;音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic 还在为小爱音箱的版权限制而烦恼吗&#xff1f;每次想听…

作者头像 李华
网站建设 2026/7/2 10:11:12

WebView 与 H5 加速

加载webview内核 设置缓存 webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);webSettings.setDatabaseEnabled(true);webSettings.setDomStorageEnabled(true);webSettings.setAppCacheEnabled(true); 在Android 4.2到Android N之间&#xff0c;系统为了组件切换的流程性考…

作者头像 李华
网站建设 2026/7/2 10:10:19

《墨香情》2026年7月最新官网下载:正统复刻水墨江湖

作为 2004 年经典端游《墨香》的正版复刻&#xff0c;《墨香情》手游由江苏三九互娱联合运营&#xff0c;旨在唤醒一代玩家的青春记忆。它并非简单的换皮之作&#xff0c;而是对原作的深度还原&#xff0c;从世界观、场景到核心玩法&#xff0c;都力求原汁原味。游戏采用纯正的…

作者头像 李华
网站建设 2026/7/2 10:10:16

智能安全测试实战:从AI原理到Strix AI工具应用指南

1. 项目概述&#xff1a;为什么我们需要“智能”的安全测试&#xff1f; 如果你和我一样&#xff0c;在安全行业摸爬滚打了十几年&#xff0c;一定经历过这样的场景&#xff1a;面对一个庞大的Web应用或者一个复杂的物联网系统&#xff0c;传统的扫描器跑了一遍又一遍&#xf…

作者头像 李华