# React Hooks 的优势和使用场景
## 1. 代码复用性提升
通过自定义Hook可以轻松提取组件逻辑,实现跨组件复用。传统高阶组件(HOC)和render props模式会导致组件树嵌套,而Hook直接在组件内部调用,保持组件扁平结构。
```jsx
// 自定义Hook示例:使用窗口大小
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
useEffect(() => {
const handleResize = () => setSize({
width: window.innerWidth,
height: window.innerHeight
});
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
// 在多个组件中使用
function ComponentA() {
const { width } = useWindowSize();
// ...
}
function ComponentB() {
const { height } = useWindowSize();
// ...
}
2. 逻辑关注点分离
类组件中相关逻辑分散在不同生命周期,Hook允许按功能组织代码,将相关逻辑集中处理。
// 传统类组件方式
class Example extends React.Component {
componentDidMount() {
// 逻辑A初始化
// 逻辑B初始化
}
componentDidUpdate() {
// 逻辑A更新
// 逻辑B更新
}
componentWillUnmount() {
// 逻辑A清理
// 逻辑B清理
}
}
// Hook方式
function Example() {
// 逻辑A相关代码
useEffect(() => {
// 初始化
return () => {
// 清理
};
}, [/* 依赖 */]);
// 逻辑B相关代码
useEffect(() => {
// 初始化
return () => {
// 清理
};
}, [/* 依赖 */]);
}
3. 简化复杂组件
使用useReducer可以更好地管理复杂状态逻辑,替代Redux的部分场景。
function todosReducer(state, action) {
switch (action.type) {
case 'add':
return [...state, action.payload];
case 'toggle':
return state.map(todo =>
todo.id === action.id ? {...todo, done: !todo.done} : todo
);
default:
throw new Error();
}
}
function Todos() {
const [todos, dispatch] = useReducer(todosReducer, []);
const handleAdd = text => {
dispatch({ type: 'add', payload: { id: Date.now(), text } });
};
// ...
}
4. 性能优化
useMemo和useCallback可以避免不必要的计算和子组件重渲染。
function ExpensiveComponent({ list }) {
const sortedList = useMemo(() => {
return list.sort((a, b) => a.value - b.value);
}, [list]);
const handleClick = useCallback(() => {
// 处理点击
}, [/* 依赖 */]);
return <Child onClick={handleClick} list={sortedList} />;
}
5. 副作用管理
useEffect统一处理副作用,替代componentDidMount、componentDidUpdate和componentWillUnmount。
function DataFetcher({ id }) {
const [data, setData] = useState(null);
useEffect(() => {
let isMounted = true;
fetchData(id).then(res => {
if (isMounted) setData(res);
});
return () => {
isMounted = false; // 清理
};
}, [id]); // id变化时重新获取
}
6. 使用场景建议
- useState: 管理简单组件状态
- useEffect: 处理副作用、订阅、定时器等
- useContext: 跨组件共享状态
- useReducer: 管理复杂状态逻辑
- useMemo/useCallback: 性能优化
- 自定义Hook: 封装可复用逻辑
7. 注意事项
- 只在顶层调用Hook,不要在循环、条件或嵌套函数中调用
- 仅在React函数组件或自定义Hook中调用Hook
- 使用eslint-plugin-react-hooks确保规则正确使用
- 复杂状态逻辑考虑使用useReducer替代多个useState
- 避免在useEffect中执行阻塞渲染的操作