React钩子在React 16.8(2019年)引入后改变了React组件的工作方式。大多数开发者可以舒适地使用useState和useEffect,但对其余钩子的理解较浅。以下是每个钩子实际上做什么以及何时使用它。
useState和useReducer:状态钩子
`useState`:管理简单的状态值。关键心理模型:调用`setState`安排重新渲染;组件重新渲染,新状态值是你传递的参数。陈旧闭包问题:如果你在闭包(setTimeout、没有适当清理添加的事件监听器、异步函数)内访问状态,你可能会看到创建闭包时的状态值,而不是当前值。修复:使用函数更新形式`setState(prev => prev + 1)`,它总是接收当前值。`useReducer`:管理更复杂的状态转换,其中下一个状态取决于动作和当前状态。模式:`const [state, dispatch] = useReducer(reducer, initialState)`,其中reducer是`(state, action) => newState`。何时使用useReducer而不是useState:当你有多个一起变化的相关状态值时;当下一个状态以复杂方式依赖于当前状态时;当状态更新逻辑足够复杂,将其移到组件外部(到纯reducer函数中)使其更可测试时。useState和useReducer之间的性能差异可以忽略不计——基于代码清晰度而非性能进行选择。
useEffect及其兄弟
`useEffect(fn, deps)`:在每次渲染后至少有一个`deps`中的值改变时运行`fn`。心理模型转变:useEffect不是生命周期方法——它是一个同步机制。问题不是”什么时候应该运行?”而是”这个副作用应该与什么状态/props同步?”清理函数:从useEffect返回的函数在下一次效果执行之前和卸载时运行——用它来取消网络请求、清除超时、删除事件监听器、取消订阅。空依赖数组`[]`:在第一次渲染后运行一次,并在卸载清理时再次运行。这是”挂载时”的等效物,但要小心——如果效果的内部代码引用未列为依赖项的变量,很容易捕获陈旧值。`useLayoutEffect`:在DOM变更之后但在浏览器绘制之前同步运行。只有在需要测量DOM元素或进行必须在绘制之前发生的DOM变更时才使用它(以避免视觉闪烁)。95%的用例中,`useEffect`是正确的。`useInsertionEffect`:仅用于CSS-in-JS库——在DOM变更之前运行。永远不要使用此钩子,除非你正在编写样式库。
useCallback、useMemo和useRef
`useCallback(fn, deps)`:记忆化一个函数——如果依赖项没有改变,在渲染之间返回相同的函数引用。用例:将回调传递给包装在`React.memo`中的子组件。没有useCallback,子组件每次父组件渲染时都会重新渲染,因为每次渲染时函数引用都是新的。过度使用问题:到处添加useCallback是一种常见的过度优化——记忆化本身有成本。只有在有不必要重新渲染证据时才添加它(React DevTools分析器)。`useMemo(fn, deps)`:记忆化函数的返回值。当计算昂贵且结果仅在特定依赖项改变时才需要时使用。测试:如果函数耗时不到1ms,useMemo添加的开销多于它节省的。`useRef(initialValue)`:创建一个可变ref对象,其`.current`属性在渲染之间持久存在,而不会导致重新渲染。两种不同的用法:访问DOM元素(`




