React Hooks 的优势和使用场景
1. Hooks 的核心优势
1.1 逻辑复用更简单
传统高阶组件(HOC)和render props模式会导致组件树嵌套过深,而Hooks通过自定义Hook实现逻辑复用:
// 自定义计数器Hook
function useCounter(initialValue) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(c => c + 1);
return { count, increment };
}
// 组件A使用
function ComponentA() {
const counter = useCounter(0);
return <button onClick={counter.increment}>{counter.count}</button>;
}
// 组件B复用相同逻辑
function ComponentB() {
const counter = useCounter(10);
return <div onClick={counter.increment}>Count: {counter.count}</div>;
}
1.2 解决class组件痛点
- 告别this绑定问题
- 生命周期逻辑更集中
- 避免不必要的组件拆分
1.3 性能优化更精细
function ExpensiveComponent() {
const [value, setValue] = useState(0);
// 只有value变化时才重新计算
const memoizedValue = useMemo(() => {
return heavyComputation(value);
}, [value]);
return <div>{memoizedValue}</div>;
}
2. 常用Hooks使用场景
2.1 useState - 状态管理
function Form() {
const [name, setName] = useState('');
const [age, setAge] = useState(18);
return (
<>
<input value={name} onChange={e => setName(e.target.value)} />
<input
type="number"
value={age}
onChange={e => setAge(Number(e.target.value))}
/>
</>
);
}
2.2 useEffect - 副作用处理
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变化时重新获取
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
2.3 useContext - 跨组件通信
const ThemeContext = 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 - 复杂状态逻辑
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:
return state;
}
}
function TodoList() {
const [todos, dispatch] = useReducer(todosReducer, []);
return (
<>
<button onClick={() => dispatch({
type: 'add',
payload: {id: Date.now(), text: 'New todo', done: false}
})}>
Add Todo
</button>
{todos.map(todo => (
<div key={todo.id}>
{todo.text}
<input
type="checkbox"
checked={todo.done}
onChange={() => dispatch({type: 'toggle', id: todo.id})}
/>
</div>
))}
</>
);
}
3. 高级应用场景
3.1 自定义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 ResponsiveComponent() {
const { width } = useWindowSize();
return <div>Window width: {width}px</div>;
}
3.2 性能优化组合
function ProductList({ products }) {
const [filter, setFilter] = useState('');
// 缓存过滤结果
const filteredProducts = useMemo(() => {
return products.filter(p =>
p.name.toLowerCase().includes(filter.toLowerCase())
);
}, [products, filter]);
// 缓存回调函数
const handleSelect = useCallback((productId) => {
console.log('Selected:', productId);
}, []);
return (
<>
<input
value={filter}
onChange={e => setFilter(e.target.value)}
placeholder="Filter products..."
/>
<ul>
{filteredProducts.map(product => (
<ProductItem
key={product.id}
product={product}
onSelect={handleSelect}
/>
))}
</ul>
</>
);
}
4. 最佳实践
-
遵循Hooks调用规则
- 只在React函数组件或自定义Hook中调用
- 不要在循环、条件或嵌套函数中调用
-
合理拆分副作用
// 不好的做法 - 混合不相关的逻辑 useEffect(() => { document.title = `You clicked ${count} times`; fetchData(userId); // 不相关的逻辑 }, [count, userId]); // 好的做法 - 分离副作用 useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); useEffect(() => { fetchData(userId); }, [userId]); -
自定义Hook命名规范
- 始终以
use开头 - 明确表达Hook的功能
- 始终以
-
性能优化时机
- 使用
useMemo处理昂贵计算 - 使用
useCallback避免不必要的子组件重渲染
- 使用
-
渐进式采用策略
- 新组件直接使用Hooks开发
- 旧组件逐步重构
Hooks为React开发带来了革命性的改变,使函数组件能够拥有类组件的所有能力,同时提供了更简洁的代码组织和更灵活的逻辑复用方式。正确使用Hooks可以显著提高代码的可维护性和可测试性。