# React Hooks 的优势和使用场景
## 核心优势
### 1. 逻辑复用更简单
通过自定义Hook可以轻松复用状态逻辑,避免高阶组件和render props的嵌套问题:
```javascript
// 自定义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 MyComponent() {
const { width } = useWindowSize();
return <div>Window width: {width}px</div>;
}
2. 代码组织更清晰
相关逻辑可以集中在一起,而不是分散在各个生命周期方法中:
function UserProfile({ userId }) {
// 状态管理集中
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
// 副作用集中
useEffect(() => {
setLoading(true);
fetchUser(userId).then(data => {
setUser(data);
setLoading(false);
});
}, [userId]);
if (loading) return <Spinner />;
return <Profile user={user} />;
}
3. 减少组件嵌套
避免为共享状态而创建多层嵌套组件:
// 使用Hook前
<ThemeProvider>
<UserProvider>
<Content />
</UserProvider>
</ThemeProvider>
// 使用Hook后
function Content() {
const theme = useTheme();
const user = useUser();
// 直接使用theme和user
}
主要使用场景
1. 状态管理
useState 适用于组件内部状态管理:
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Clicked {count} times
</button>
);
}
2. 副作用处理
useEffect 处理数据获取、订阅等副作用:
function DataFetcher({ url }) {
const [data, setData] = useState(null);
useEffect(() => {
let ignore = false;
fetch(url)
.then(res => res.json())
.then(data => !ignore && setData(data));
return () => { ignore = true; };
}, [url]);
return <div>{JSON.stringify(data)}</div>;
}
3. 性能优化
useMemo 和 useCallback 用于避免不必要的计算和渲染:
function ExpensiveComponent({ items, filter }) {
const filteredItems = useMemo(() => {
return items.filter(item => item.includes(filter));
}, [items, filter]);
const handleClick = useCallback(() => {
console.log('Item clicked');
}, []);
return <List items={filteredItems} onClick={handleClick} />;
}
4. 访问上下文
useContext 简化上下文使用:
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click me</button>;
}
5. 引用DOM元素
useRef 用于访问DOM节点或保存可变值:
function TextInput() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</>
);
}
最佳实践
- 只在顶层调用Hook:不要在循环、条件或嵌套函数中调用Hook
- 按逻辑分组:将相关的state和effect放在一起
- 合理使用依赖数组:确保useEffect依赖项完整
- 自定义Hook命名:以use开头命名自定义Hook
- 适度拆分:当组件逻辑复杂时,拆分为多个自定义Hook
注意事项
- 不要滥用useEffect:避免在useEffect中做太多事情
- 性能敏感场景:对于高频更新使用useReducer而非useState
- 复杂状态逻辑:当state相互依赖时