
核心目标:减少不必要渲染、降低计算开销。
用 React.memo 缓存组件
对纯展示组件使用React.memo,避免父组件重渲染时自身无意义更新。
// 案例:缓存用户卡片组件
const UserCard = React.memo(({ name, age }) => {
console.log("UserCard渲染"); // 仅name/age变化时触发
return <div>{name} ({age})</div>;
});用 useMemo 缓存计算结果
避免重复执行耗时计算(如数据排序、过滤)。
// 案例:缓存排序后的列表
const sortedList = useMemo(() => {
return list.sort((a, b) => a.score - b.score); // 仅list变化时重算
}, [list]);
用 useCallback 缓存函数引用
防止因函数重新创建导致子组件(如UserCard)误触发渲染。
// 案例:缓存事件处理函数
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]); // 仅count变化时更新函数引用虚拟列表优化长列表
仅渲染可视区域内的列表项(推荐react-window库)。
// 案例:用FixedSizeList实现长列表
import { FixedSizeList as List } from "react-window";
const LongList = ({ data }) => (
<List height={400} width={300} itemCount={data.length} itemSize={50}>
{({ index, style }) => (
<div style={style}>{data[index].name}</div>
)}
</List>
);
懒加载组件(React.lazy + Suspense)
拆分代码包,仅在组件需要时加载(如路由组件)。
// 案例:懒加载订单页面
const OrderPage = React.lazy(() => import("./OrderPage"));
const App = () => (
<Suspense fallback={<div>加载中...</div>}>
<Route path="/order" component={OrderPage} />
</Suspense>
);避免直接修改 state
直接修改 state 不会触发组件重渲染,需用新引用(如展开运算符)。
// 错误:直接修改
const handleUpdate = () => {
user.age = 20; // 无重渲染
setUser(user);
};
// 正确:生成新对象
const handleUpdate = () => {
setUser({ ...user, age: 20 }); // 触发重渲染
};
用 useTransition 标记非紧急更新
优先执行用户交互(如输入),延迟执行低优先级更新(如列表过滤)。
// 案例:输入时延迟过滤列表
const [search, setSearch] = useState("");
const [filteredList, setFilteredList] = useState([]);
const handleSearch = (e) => {
const value = e.target.value;
setSearch(value); // 紧急更新(输入框)
// 非紧急更新(列表过滤)
startTransition(() => {
setFilteredList(list.filter(item => item.name.includes(value)));
});
};优化 context 渲染
将 context 拆分为多个小 context,避免一个值变化导致所有消费组件重渲染。
// 案例:拆分用户信息和主题context
const UserContext = createContext();
const ThemeContext = createContext();
// 消费时仅依赖需要的context
const Component = () => {
const user = useContext(UserContext); // 仅UserContext变化时重渲染
return <div>{user.name}</div>;
};
用 useRef 保存不变值
存储不需要触发重渲染的值(如定时器 ID、DOM 元素)。
// 案例:保存定时器ID
const timerRef = useRef(null);
const startTimer = () => {
timerRef.current = setInterval(() => {
setCount(c => c + 1);
}, 1000);
};
const stopTimer = () => {
clearInterval(timerRef.current);
};避免在渲染时创建函数 / 对象
渲染时创建的新引用会导致
useMemo/useCallback/React.memo失效。
// 错误:渲染时创建对象
<UserCard user={{ name: "张三" }} /> // 每次渲染都是新对象,memo失效
// 正确:用state/useMemo缓存
const user = useMemo(() => ({ name: "张三" }), []);
<UserCard user={user} />