# React Hooks 的优势和使用场景
## 1. Hooks 的核心优势
### 1.1 逻辑复用更简单
通过自定义 Hook 可以提取组件逻辑,使状态逻辑复用变得简单。相比 HOC 和 Render Props 模式,Hook 不会产生嵌套地狱。
```jsx
// 自定义计数器 Hook
function useCounter(initialValue) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(c => c + 1);
return { count, increment };
}
// 组件中使用
function MyComponent() {
const { count, increment } = useCounter(0);
return <button onClick={increment}>{count}</button>;
}
1.2 代码组织更清晰
相关逻辑可以集中在一起,而不是分散在各个生命周期方法中。
function UserProfile({ userId }) {
// 状态管理集中
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
// 副作用集中
useEffect(() => {
const fetchUser = async () => {
setLoading(true);
const response = await fetch(`/users/${userId}`);
setUser(await response.json());
setLoading(false);
};
fetchUser();
}, [userId]);
if (loading) return <Spinner />;
return <Profile user={user} />;
}
1.3 减少组件嵌套
不再需要为了复用状态逻辑而创建包装组件,减少了组件树的嵌套层级。
2. 常用 Hooks 使用场景
2.1 useState - 状态管理
适用于组件内部的状态管理,替代类组件的 this.state。
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
2.2 useEffect - 副作用处理
处理数据获取、订阅、手动修改 DOM 等副作用操作,可以替代 componentDidMount、componentDidUpdate 和 componentWillUnmount。
function WindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return <div>Window width: {width}</div>;
}
2.3 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 style={{ background: theme === 'dark' ? '#333' : '#FFF' }}>
Current theme: {theme}
</div>;
}
2.4 useReducer - 复杂状态逻辑
适合管理包含多个子值的复杂 state 逻辑,或者下一个 state 依赖于之前的 state。
function todosReducer(state, action) {
switch (action.type) {
case 'add':
return [...state, { text: action.text, completed: false }];
case 'toggle':
return state.map((todo, i) =>
i === action.index ? {...todo, completed: !todo.completed} : todo
);
default:
return state;
}
}
function TodoList() {
const [todos, dispatch] = useReducer(todosReducer, []);
function handleAdd(text) {
dispatch({ type: 'add', text });
}
// ...
}
2.5 useMemo/useCallback - 性能优化
用于优化计算开销大的操作和避免不必要的子组件重新渲染。
function Parent({ a, b }) {
// 只有 a 变化时才会重新计算
const memoizedValue = useMemo(() => computeExpensiveValue(a), [a]);
// 只有 b 变化时才会重新创建函数
const memoizedCallback = useCallback(() => doSomething(b), [b]);
return <Child callback={memoizedCallback} />;
}
3. 使用 Hooks 的最佳实践
- **只在顶层调用 Hook