# React Hooks 的优势和使用场景
## 核心优势
1. **逻辑复用更简单**
- 替代高阶组件和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;
}
-
代码组织更清晰
- 相关逻辑集中管理(对比class组件的生命周期分散)
- 减少不必要的嵌套层级
-
学习成本更低
- 无需理解this绑定
- 无需区分类组件和函数组件
-
性能优化更精细
- 可针对特定state进行优化
- 避免不必要的生命周期执行
主要Hooks使用场景
useState
- 管理组件内部状态
- 适合简单状态管理
const [count, setCount] = useState(0);
useEffect
- 副作用处理(数据获取、订阅、手动DOM操作)
- 替代componentDidMount、componentDidUpdate和componentWillUnmount
useEffect(() => {
// 组件挂载时执行
const subscription = props.source.subscribe();
return () => {
// 组件卸载时执行清理
subscription.unsubscribe();
};
}, [props.source]); // 仅在props.source变化时重新执行
useContext
- 跨组件共享状态
- 替代部分Redux场景
const theme = useContext(ThemeContext);
useReducer
- 复杂状态逻辑管理
- 适合状态更新逻辑复杂的场景
const [state, dispatch] = useReducer(reducer, initialState);
useCallback
- 缓存回调函数
- 避免子组件不必要的重渲染
const memoizedCallback = useCallback(
() => { doSomething(a, b); },
[a, b],
);
useMemo
- 缓存计算结果
- 性能优化手段
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useRef
- 访问DOM节点
- 保存可变值(不触发重渲染)
const inputEl = useRef(null);
const onButtonClick = () => inputEl.current.focus();
最佳实践
-
Hook调用规则
- 只在React函数组件或自定义Hook中调用
- 不要在循环、条件或嵌套函数中调用
-
性能优化
- 合理使用依赖数组
- 避免在useEffect中执行不必要的操作
-
自定义Hook规范
- 命名以use开头
- 可组合使用内置Hook
-
代码组织建议
- 相关逻辑组织在一起
- 复杂组件可拆分为多个自定义Hook
适用场景
-
新项目开发
- 优先使用函数组件+Hook模式
-
旧项目改造
- 逐步替换class组件
- 优先改造复杂生命周期组件
-
状态管理
- 简单场景:useState/useReducer
- 复杂场景:结合Context API或状态管理库
-
副作用处理
- 数据获取、事件监听等场景使用useEffect
注意事项
-
不要滥用useEffect
- 避免在单个组件中使用过多useEffect
- 考虑将相关逻辑提取到自定义Hook
-
依赖数组要完整
- 确保包含所有外部依赖
- 使用eslint-plugin-react-hooks插件检查
-
避免过度优化
- 只在必要时使用useCallback/useMemo
- 通过性能测试验证优化效果
-
class组件仍有价值
- 错误边界等特殊场景仍需class组件
- 不必强制转换所有现有组件