React 自 16.8 版本引入 Hooks 以来,逐渐成为函数组件开发的主流方式。除了经典的 useState 和 useEffect,React 还推出了一些新的 Hooks,用于解决更复杂的状态管理、性能优化和副作用处理问题。以下是 React 中一些重要的新 Hooks 及其用途:
一、核心新 Hooks
1. useReducer
-
用途:用于管理复杂的状态逻辑,类似于 Redux 的 reducer 模式。
-
适用场景:状态逻辑复杂、需要多个子状态或依赖前一个状态的场景。
const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({ type: 'increment' })}>+</button> <button onClick={() => dispatch({ type: 'decrement' })}>-</button> </> ); }
2. useContext
-
用途:用于在组件树中共享状态,避免逐层传递 props。
-
适用场景:主题切换、用户认证、多语言等全局状态管理。
const ThemeContext = React.createContext('light'); function App() { return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar() { const theme = useContext(ThemeContext); return <div>Current theme: {theme}</div>; }
3. useRef
-
用途:用于保存可变值(如 DOM 引用或计时器 ID),且在组件重新渲染时不会触发更新。
-
适用场景:访问 DOM 元素、保存上一次的值、避免重复渲染。
function TextInput() { const inputRef = useRef(null); const focusInput = () => { inputRef.current.focus(); }; return ( <> <input ref={inputRef} type="text" /> <button onClick={focusInput}>Focus Input</button> </> ); }
4. useMemo
-
用途:用于缓存计算结果,避免在每次渲染时重复计算。
-
适用场景:计算密集型操作、优化性能。
function ExpensiveComponent({ a, b }) { const result = useMemo(() => { return a + b; // 仅当 a 或 b 变化时重新计算 }, [a, b]); return <div>Result: {result}</div>; }
5. useCallback
-
用途:用于缓存函数引用,避免在每次渲染时创建新的函数。
-
适用场景:优化子组件性能(避免不必要的重新渲染)。
function ParentComponent() { const [count, setCount] = useState(0); const handleClick = useCallback(() => { setCount((prev) => prev + 1); }, []); // 空依赖数组表示函数不会变化 return <ChildComponent onClick={handleClick} />; }
二、高级新 Hooks
1. useLayoutEffect
-
用途:与
useEffect类似,但在浏览器完成布局和绘制之前同步执行。 -
适用场景:需要直接操作 DOM 或测量布局的场景。
function MeasureComponent() { const [width, setWidth] = useState(0); const ref = useRef(null); useLayoutEffect(() => { setWidth(ref.current.offsetWidth); }, []); return <div ref={ref}>Width: {width}px</div>; }
2. useImperativeHandle
-
用途:用于自定义暴露给父组件的实例值或方法。
-
适用场景:封装第三方库或需要暴露特定方法的场景。
function FancyInput(props, ref) { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); }, })); return <input ref={inputRef} />; } FancyInput = forwardRef(FancyInput); function Parent() { const inputRef = useRef(); return ( <> <FancyInput ref={inputRef} /> <button onClick={() => inputRef.current.focus()}>Focus Input</button> </> ); }
3. useDebugValue
-
用途:用于在 React 开发者工具中显示自定义 Hook 的调试信息。
-
适用场景:开发自定义 Hook 时提供调试支持。
function useCustomHook() { const [value] = useState('Hello'); useDebugValue(value); // 在开发者工具中显示 value return value; }
三、React 18 新增 Hooks
1. useId
-
用途:生成唯一的 ID,用于关联 DOM 元素(如
<label>和<input>)。 -
适用场景:表单控件、无障碍支持。
function Checkbox() { const id = useId(); return ( <> <label htmlFor={id}>Do you like React?</label> <input id={id} type="checkbox" /> </> ); }
2. useSyncExternalStore
-
用途:用于订阅外部数据源(如 Redux、Zustand)的状态。
-
适用场景:集成第三方状态管理库。
const store = { getState: () => ({ count: 0 }), subscribe: (listener) => { window.addEventListener('storage', listener); return () => window.removeEventListener('storage', listener); }, }; function Counter() { const state = useSyncExternalStore(store.subscribe, store.getState); return <div>Count: {state.count}</div>; }
3. useInsertionEffect
-
用途:用于在 DOM 更新之前插入样式或其他元素。
-
适用场景:动态注入 CSS 或处理布局抖动。
function useCustomStyle(style) { useInsertionEffect(() => { const styleElement = document.createElement('style'); styleElement.textContent = style; document.head.appendChild(styleElement); return () => document.head.removeChild(styleElement); }, [style]); }
四、总结
| Hook | 用途 |
|---|---|
useReducer | 管理复杂状态逻辑。 |
useContext | 共享全局状态。 |
useRef | 保存可变值或 DOM 引用。 |
useMemo | 缓存计算结果,优化性能。 |
useCallback | 缓存函数引用,优化子组件性能。 |
useLayoutEffect | 同步执行副作用,操作 DOM 或测量布局。 |
useImperativeHandle | 自定义暴露给父组件的实例值或方法。 |
useDebugValue | 在开发者工具中显示自定义 Hook 的调试信息。 |
useId | 生成唯一 ID,用于表单控件或无障支持。 |
useSyncExternalStore | 订阅外部数据源的状态。 |
useInsertionEffect | 在 DOM 更新之前插入样式或处理布局抖动。 |
这些 Hooks 极大地扩展了 React 函数组件的能力,使其能够处理更复杂的场景,同时保持代码的简洁性和可维护性。