React Hooks 深入理解
React Hooks 是 React 16.8 引入的新特性,它让你可以在函数组件中使用状态和其他 React 特性。
为什么需要 Hooks?
Hooks 解决了类组件的几个问题:
- 组件逻辑复用困难(HOC、Render Props 复杂)
- 类组件难以理解和维护
- 组件间逻辑共享代码复杂
常用 Hooks
useState
function Counter() { const [count, setCount] = useState(0);
return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>+</button> </div> ); }
|
useEffect
useEffect(() => { document.title = `You clicked ${count} times`; return () => { document.title = 'React App'; }; }, [count]);
|
useContext
const ThemeContext = React.createContext('light');
function ThemedButton() { const theme = useContext(ThemeContext); return <button className={theme}>I am styled by theme context!</button>; }
|
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
|
useCallback
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
|
自定义 Hooks
function useWindowWidth() { const [width, setWidth] = useState(window.innerWidth); useEffect(() => { const handleResize = () => setWidth(window.innerWidth); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return width; }
function App() { const width = useWindowWidth(); return <p>Window width: {width}</p>; }
|
规则和最佳实践
- 只在顶层调用 Hooks:不要在循环、条件语句或嵌套函数中调用 Hooks
- 只在 React 函数中调用 Hooks:在 React 函数组件或自定义 Hook 中调用
- 命名规范:以
use 开头,如 useMyCustomHook
性能优化
const MemoizedComponent = React.memo(MyComponent);
function BigList({ items }) { const renderRow = useCallback( (index) => <Row item={items[index]} />, [items] ); return <List itemCount={items.length} renderRow={renderRow} />; }
|
Hooks 设计模式
条件 Hook
function useFormInput(initialValue) { const [value, setValue] = useState(initialValue); return { value, onChange: (e) => setValue(e.target.value), reset: () => setValue(initialValue) }; }
|
组合模式
function useDataFetching(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { const fetchData = async () => { try { const response = await fetch(url); const data = await response.json(); setData(data); } catch (err) { setError(err); } finally { setLoading(false); } };
fetchData(); }, [url]);
return { data, loading, error }; }
|
常见问题解决
避免闭包陷阱
function Counter() { const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={increment}>+</button> </div> ); }
function Counter() { const [count, setCount] = useState(0); const increment = () => { setCount(c => c + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={increment}>+</button> </div> ); }
|
[!tip]
使用 useCallback 包装事件处理函数,避免不必要的重新渲染。
总结
React Hooks 提供了一种更简洁、更直观的方式来编写 React 组件。掌握 Hooks 可以让你写出更好的 React 代码。
参考资料