React 常用 Hooks 使用指南
useState、useEffect、useMemo、useCallback、useRef、useContext 的用法与示例
问题
介绍 React 中六个常用 Hooks 的用法:useState、useEffect、useMemo、useCallback、useRef、useContext。
解答
useState
管理组件状态。
import { useState } from 'react';
function Counter() {
// 声明状态变量 count,初始值为 0
const [count, setCount] = useState(0);
// 函数式更新:基于前一个状态计算新状态
const increment = () => setCount(prev => prev + 1);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+1</button>
</div>
);
}
useEffect
处理副作用:数据请求、订阅、DOM 操作等。
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// 副作用:请求数据
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
// 清理函数:组件卸载或 userId 变化时执行
return () => {
console.log('cleanup');
};
}, [userId]); // 依赖数组:userId 变化时重新执行
return <div>{user?.name}</div>;
}
useMemo
缓存计算结果,避免重复计算。
import { useState, useMemo } from 'react';
function ExpensiveList({ items, filter }) {
// 只有 items 或 filter 变化时才重新计算
const filteredItems = useMemo(() => {
console.log('filtering...');
return items.filter(item => item.includes(filter));
}, [items, filter]);
return (
<ul>
{filteredItems.map(item => <li key={item}>{item}</li>)}
</ul>
);
}
useCallback
缓存函数引用,避免子组件不必要的重渲染。
import { useState, useCallback, memo } from 'react';
// 子组件用 memo 包裹,只有 props 变化才重渲染
const Button = memo(({ onClick, children }) => {
console.log('Button render');
return <button onClick={onClick}>{children}</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
// 缓存函数,count 变化时才创建新函数
const increment = useCallback(() => {
setCount(c => c + 1);
}, []);
return (
<div>
<input value={text} onChange={e => setText(e.target.value)} />
<Button onClick={increment}>Count: {count}</Button>
</div>
);
}
useRef
保存可变值,不触发重渲染;访问 DOM 元素。
import { useRef, useEffect } from 'react';
function TextInput() {
// 引用 DOM 元素
const inputRef = useRef(null);
// 保存可变值(不触发重渲染)
const renderCount = useRef(0);
useEffect(() => {
// 组件挂载后自动聚焦
inputRef.current.focus();
// 记录渲染次数
renderCount.current += 1;
});
return (
<div>
<input ref={inputRef} placeholder="自动聚焦" />
<p>渲染次数: {renderCount.current}</p>
</div>
);
}
useContext
跨组件传递数据,避免 props 层层传递。
import { createContext, useContext, useState } from 'react';
// 1. 创建 Context
const ThemeContext = createContext('light');
// 2. 子组件消费 Context
function ThemedButton() {
const theme = useContext(ThemeContext);
return (
<button style={{
background: theme === 'dark' ? '#333' : '#fff',
color: theme === 'dark' ? '#fff' : '#333'
}}>
当前主题: {theme}
</button>
);
}
// 3. 父组件提供 Context
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<ThemedButton />
<button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
切换主题
</button>
</ThemeContext.Provider>
);
}
关键点
- useState:状态更新是异步的,用函数式更新获取最新值
- useEffect:依赖数组为空
[]只执行一次,不传则每次渲染都执行 - useMemo:缓存值,适合计算开销大的场景
- useCallback:缓存函数,配合
memo优化子组件渲染 - useRef:
.current修改不触发重渲染,常用于存 DOM 引用或定时器 ID - useContext:适合全局状态(主题、用户信息),频繁更新的状态不适合用 Context
目录