文章目录一、React 进阶技巧useState 函数式更新Functional Updates1. 四大核心好处A. 确保获取“最新的”状态解决闭包陷阱B. 减少 Hook 的依赖项性能优化C. 在异步逻辑中保证安全性D. 逻辑解耦React 进阶笔记useContext 全解析1. 什么是 useContext2. 核心使用流程三部曲第一步创建 Context第二步提供 Provider第三步消费 Context3. seContext 的四大进阶用法① 动态更新 Context② 封装自定义 Provider工程化实践③ 自定义 Hook 简化调用4. 性能陷阱与优化方案5. useContext vs. Redux怎么选6. 核心概念总结三、 useReducer 深度解析1. 核心概念三个核心角色2. 基本语法3. 实战演练计数器例子1. 定义 Reducer 函数2. 在组件中使用React 状态管理对比useState vs useReducer 选型建议4. 进阶技巧1. 传递 Payload载荷2. 惰性初始化四、React 状态管理指南useState vs useReducer一、 深度对比useReducer 的核心优势1. 逻辑解耦将“做什么”与“怎么做”分开2. 状态依赖关系的完美处理3. 性能优化稳定的引用二、 场景模拟你应该如何选择三、 决策树三步定乾坤四、 进阶建议什么时候不该用 useReducer五、 一句话总结一、React 进阶技巧useState 函数式更新Functional Updates在 React 开发中函数式更新是指向setState传递一个回调函数而不是直接传递一个值。这是处理复杂状态逻辑和性能优化的核心手段。// 普通更新setCount(count1);// 函数式更新setCount(prevCountprevCount1);1. 四大核心好处A. 确保获取“最新的”状态解决闭包陷阱React 的 setState 是异步执行的在同一个事件循环中会进行批处理。如果你在短时间内连续调用多次普通更新可能会因为闭包导致拿到的状态是“旧的”。错误场景普通更新consthandleAdd(){setCount(count1);setCount(count1);setCount(count1);};// 结果count 只增加了 1。因为三次调用时count 的值都是同一个快照。正确场景函数式更新consthandleAdd(){setCount(prevprev1);setCount(prevprev1);setCount(prevprev1);};// 结果count 增加了 3。React 会保证 prev 总是上一次更新操作后的最新状态。B. 减少 Hook 的依赖项性能优化这是配合 useEffect、useCallback 或 useMemo 时最强大的好处。使用函数式更新可以移除依赖项防止 Hook 频繁触发或导致子组件重绘。// ❌ 必须依赖 count导致 handleClick 每次 count 变动都重新生成consthandleClickuseCallback((){setCount(count1);},[count]);// ✅ 不需要依赖 counthandleClick 引用保持稳定consthandleClickuseCallback((){setCount(prevprev1);},[]);注这对于配合 React.memo 优化子组件性能极其重要。C. 在异步逻辑中保证安全性在 setTimeout、setInterval 或网络请求回调中由于闭包效应直接访问的状态变量往往是函数创建时的旧值。useEffect((){consttimersetInterval((){// 如果这里写 setCount(count 1)count 将由于闭包永远锁定在初始值setCount(prevprev1);},1000);return()clearInterval(timer);},[]);// 依赖为空timer 仅在挂载时创建一次D. 逻辑解耦函数式更新允许你将“如何更新状态”的逻辑提取到组件外部。因为更新函数不再依赖组件内部的具体变量它变成了一个纯函数。// 逻辑可以定义在组件外部甚至跨文件复用constincrement(prev)prev1;functionCounter(){const[count,setCount]useState(0);returnbutton onClick{()setCount(increment)}/button;}React 进阶笔记useContext 全解析这是一个关于useContext的全方位教程笔记旨在帮助你彻底理清 Context API 的使用逻辑、应用场景以及性能优化方案。1. 什么是 useContext在 React 中数据通常通过 props 自上而下传递。但当组件嵌套层级过深时例如根组件 - 导航栏 - 用户面板 - 用户头像这种逐级传递Prop Drilling会变得极其痛苦。useContext允许我们创建一个“全局广播系统”让任何层级的子组件都能直接获取到顶层定义的数据而无需通过 props 中转。2. 核心使用流程三部曲第一步创建 Context使用createContext创建一个上下文对象。通常单独放在一个文件中。// ThemeContext.jsimport{createContext}fromreact;// light 是默认值仅在组件未被 Provider 包裹时生效exportconstThemeContextcreateContext(light);第二步提供 Provider在父组件中使用 ThemeContext.Provider 包裹子组件并通过 value 属性下发数据。import{useState}fromreact;import{ThemeContext}from./ThemeContext;functionApp(){const[theme,setTheme]useState(dark);return(ThemeContext.Provider value{theme}MainPage//ThemeContext.Provider);}第三步消费 Context在任何子组件中调用 useContext Hook 即可获取数据。import{useContext}fromreact;import{ThemeContext}from./ThemeContext;functionUserPanel(){constthemeuseContext(ThemeContext);// 直接拿到 darkreturndiv className{theme}当前主题{theme}/div;}3. seContext 的四大进阶用法① 动态更新 Context如果你需要子组件修改 Context可以将 state 和 setState 一起放入 value 中。// Provider 传递对象ThemeContext.Provider setTheme theme,value{{}}{children}/ThemeContext.Provider// 子组件中调用const{theme,setTheme}useContext(ThemeContext);button onClick{()setTheme(light)}切换主题/button② 封装自定义 Provider工程化实践为了保持组件整洁通常会将逻辑封装在独立组件中。exportfunctionThemeProvider({children}){const[theme,setTheme]useState(light);consttoggleTheme()setTheme(ttlight?dark:light);return(ThemeContext.Provider theme,toggleTheme value{{}}{children}/ThemeContext.Provider);}③ 自定义 Hook 简化调用为了避免每次都要重复导入 ThemeContext 和 useContext建议封装一个自定义 Hook。exportconstuseTheme(){constcontextuseContext(ThemeContext);if(!context){thrownewError(useTheme 必须在 ThemeProvider 内部使用);}returncontext;};4. 性能陷阱与优化方案性能痛点无效重渲染当 Context 的 value 发生变化时所有使用了 useContext(MyContext) 的子组件都会强制重新渲染即使它们只使用了对象中未改变的部分。优化手段拆分 Context不要把所有全局状态用户信息、主题、国际化塞进一个 Context。按功能拆分减少不必要的更新范围。Memo 保护配合 React.memo 使用确保非相关组件不触发计算。useMemo 缓存 ValueconstvalueuseMemo(()({theme,toggleTheme}),[theme]);return(ThemeContext.Provider value{value}{children}/ThemeContext.Provider);5. useContext vs. Redux怎么选维度useContext useStateRedux / Zustand上手难度极低React 原生支持较高需学习新概念性能中等复杂场景易导致全量渲染优秀有精准的订阅机制调试工具React DevToolsRedux DevTools (强大)适用场景低频更新主题、语言、用户信息。高频更新/大型应用电商购物车、协作工具。6. 核心概念总结关键词解释createContext创建上下文定义默认值。Provider生产者通过value属性广播数据。useContext消费者在子组件中提取数据。Prop Drilling痛点指属性像钻头一样层层穿透中间组件。金句总结“Context 不是为了取代 Props而是为了终结那些为了传值而传值的中间层组件。它是 React 的全局任意门但门开多了性能也会迷路。”三、 useReducer 深度解析useReducer是 React 提供的一个用于状态管理的 Hook它是useState的替代方案。当你发现组件的状态逻辑变得复杂例如一个状态依赖于另一个状态或者有多个子状态需要同步更新时useReducer就是你的最佳拍档。1. 核心概念三个核心角色理解useReducer的关键在于弄清楚这三个“演员”的关系State (状态)当前的数据源比如count: 0。Action (动作)描述发生了什么的对象比如{ type: increment }。Reducer (处理函数)一个纯函数接收当前的 State 和 Action并返回新的 State。2. 基本语法const[state,dispatch]useReducer(reducer,initialState);state当前的状态值。dispatch一个分发函数用来发送 action。调用它会触发 reducer 执行。reducer处理逻辑的函数。initialState初始状态。3. 实战演练计数器例子1. 定义 Reducer 函数Reducer 必须是一个纯函数。它不应该有副作用如 API 请求只负责计算新状态。functionreducer(state,action){// 根据 action 的类型来决定如何更新状态switch(action.type){caseincrement:return{count:state.count1};casedecrement:return{count:state.count-1};casereset:return{count:0};default:thrownewError(未知操作);}}2. 在组件中使用importReact,{useReducer}fromreact;functionCounter(){constinitialState{count:0};const[state,dispatch]useReducer(reducer,initialState);return(h1当前计数{state.count}/h1{/* 通过 dispatch 发送 action */}button onClick{()dispatch({type:increment})}/buttonbutton onClick{()dispatch({type:decrement})}-/buttonbutton onClick{()dispatch({type:reset})}重置/button/);}React 状态管理对比useState vs useReducer特性useStateuseReducer数据类型JS 基础类型Number, String或简单对象复杂的 Object、Array多个互相关联的状态逻辑位置散落在组件内部的各个函数中集中在 reducer 函数中逻辑清晰可维护性状态多了以后代码会变得凌乱非常适合大型组件方便调试和测试性能优化每次更新都可能创建新函数可以通过 dispatch 传递给子组件配合memo减少重绘 选型建议优先使用useState当状态是独立的如isOpen,inputValue或者逻辑比较简单时。考虑使用useReducer当一个动作需要同时更新多个状态或者下一个状态依赖于前一个状态的复杂计算时。4. 进阶技巧1. 传递 Payload载荷有时候我们不仅要告诉 Reducer “做什么”还要传递具体的数据。// 1. dispatch 时携带数据dispatch({type:set_count,payload:10});// 2. reducer 中接收数据caseset_count:return{count:action.payload};2. 惰性初始化如果初始状态需要通过复杂计算获得可以传入第三个参数 init 函数。这样初始状态只会计算一次避免重复计算损耗性能。const[state,dispatch]useReducer(reducer,initialArg,init);四、React 状态管理指南useState vs useReducer在 React 开发中useState和useReducer就像是工具箱里的“螺丝刀”与“电钻”一个轻巧便捷一个马力十足。虽然它们都能管理状态但底层的思维模型完全不同。一、 深度对比useReducer 的核心优势1. 逻辑解耦将“做什么”与“怎么做”分开useState状态更新逻辑通常写在事件处理函数中。当逻辑复杂时你的组件会充斥着大量的更新代码。useReducer组件只负责发送指令Dispatch Action而复杂的逻辑被集中封装在reducer纯函数中。这让组件变得非常干净只关注 UI 展示。2. 状态依赖关系的完美处理当你的下一个状态依赖于上一个状态或者多个状态需要同时更新时useState容易出现闭包陷阱或逻辑散乱。场景例子在一个表单中点击“重置”需要同时清空 5 个输入框、重置校验状态并关闭加载动画。useReducer只需要一行dispatch({ type: RESET })就能在 reducer 里统一完成保证了原子性。3. 性能优化稳定的引用dispatch函数在组件的整个生命周期中是地址不变的。这意味着你可以放心地将dispatch传递给子组件而不需要担心触发子组件的不必要重绘配合React.memo。相比之下useState的更新函数虽然也稳定但当逻辑需要包裹多层useCallback时代码会变得极其臃肿。二、 场景模拟你应该如何选择为了直观决定可以参考下表维度推荐使用useState推荐使用useReducer状态复杂度基础类型数字、布尔或简单对象嵌套对象、数组或多个互相影响的状态逻辑复杂度简单的更新如setCount(c 1)复杂的业务逻辑需要switch/case区分关联性各个状态独立如name和age状态间有关联如loading随data改变组件规模中小型组件逻辑不跨组件大型组件或需要深度传递状态的场景测试需求较难独立测试 UI 中的逻辑极佳。reducer 是纯函数可脱离 UI 测试三、 决策树三步定乾坤当你犹豫不决时问自己三个问题“我的状态变量是否超过 3-5 个且互有关联”如果是例如处理一个复杂的注册表单选useReducer。“我是否需要把状态更新逻辑传给深层的子组件”如果是选useReducer配合 Context API 效果更佳能避免 Prop Drilling。“我是不是在写类似setA(a 1); setB(!b); setC(data);这种连续调用”如果是说明这些状态属于同一个“事务”选useReducer。四、 进阶建议什么时候不该用 useReducer过度设计如果只是控制一个isOpen的开关非要写 reducer、action 和 dispatch那就是在浪费生命增加代码阅读负担。异步逻辑记住reducer 必须是纯函数。如果你有大量的fetch请求逻辑应该写在useEffect或自定义 Hook 中最后只把结果 dispatch 给 reducer。五、 一句话总结用useState处理局部、简单、独立的小状态用useReducer处理全局、复杂、关联的业务逻辑。