Yasin

Yasin

React 性能优化方法

React 性能优化方法


1. 避免不必要的重新渲染

React.memo(缓存组件)

const Child = React.memo(({ name }: { name: string }) => {
  return <div>{name}</div>;
});

props 没变就跳过渲染。

useCallback(缓存函数引用)

const handleClick = useCallback(() => {
  console.log(count);
}, [count]);

防止父组件重渲染时,函数引用变化导致子组件不必要的渲染。

useMemo(缓存计算结果)

const result = useMemo(() => {
  return heavyCalc(list);
}, [list]);

避免每次渲染都重复计算。


2. 合理拆分组件和状态

状态放到离它最近的组件,避免顶层 state 变化导致大范围重渲染:

// ❌ 不好:count 在顶层,变化导致整棵树渲染
function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <HeavyList /> {/* 和 count 无关,却被迫重渲染 */}
      <Counter count={count} onChange={setCount} />
    </>
  );
}

// ✅ 好:count 状态下移到 Counter 内部
function App() {
  return (
    <>
      <HeavyList />
      <Counter />
    </>
  );
}

3. 列表渲染加 key

items.map((item) => <Item key={item.id} data={item} />);

正确的 key 帮助 React diff 算法复用节点,避免不必要的重建。


4. 懒加载组件(代码分割)

import { lazy, Suspense } from "react";

const HeavyPage = lazy(() => import("./HeavyPage"));

function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <HeavyPage />
    </Suspense>
  );
}

按需加载,减少首屏 JS 体积。


5. 虚拟列表(长列表优化)

大量列表只渲染可视区域的元素:

import { FixedSizeList } from "react-window";

<FixedSizeList height={600} itemCount={10000} itemSize={50} width="100%">
  {({ index, style }) => <div style={style}>{index}</div>}
</FixedSizeList>;

常用库:react-windowreact-virtual


6. Context 性能优化

Context value 变化会导致所有消费组件重渲染,可以用 useMemo 稳定引用:

const value = useMemo(() => ({ theme, toggleTheme }), [theme]);

<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;

或拆分读写 Context:

<ThemeStateContext.Provider value={theme}>
  <ThemeDispatchContext.Provider value={toggleTheme}>
    {children}
  </ThemeDispatchContext.Provider>
</ThemeStateContext.Provider>

7. 图片/资源懒加载

<img src="large.jpg" loading="lazy" alt="图片" />

8. 避免在渲染中创建新对象/函数

// ❌ 每次渲染都创建新对象,导致子组件重渲染
<Child style={{ color: "red" }} />;

// ✅ 提到组件外或用 useMemo
const style = { color: "red" };
<Child style={style} />;

9. useTransition(React 18,并发优化)

把非紧急更新标记为低优先级,不阻塞用户交互:

const [isPending, startTransition] = useTransition();

startTransition(() => {
  setList(heavyFilter(data)); // 低优先级更新
});

10. useDeferredValue(React 18)

延迟某个值的更新,类似防抖:

const deferredQuery = useDeferredValue(query);

const result = useMemo(() => {
  return heavySearch(deferredQuery);
}, [deferredQuery]);

总结

方法 解决什么问题
React.memo 避免子组件不必要渲染
useCallback 稳定函数引用
useMemo 缓存计算结果
状态下移 减少渲染范围
key 优化列表 diff
懒加载 减少首屏体积
虚拟列表 长列表性能
useTransition 并发非紧急更新

最重要的原则:先测量再优化,不要过早优化。