React.memo使用

209 阅读3分钟

React.memo 是 React 的 性能优化工具,用于避免不必要的重新渲染。然而,在某些情况下,不使用 React.memo 可能是更好的选择。以下是几种不适合使用 React.memo 的情况:

1️⃣ 组件的 props 变化频繁

如果组件的 props 每次都会变化(例如,传递的是新的对象、数组、函数等),React.memo 可能不会带来优化,反而会增加不必要的对比计算成本。

🔴 不要使用 React.memo 的例子

const MyComponent = React.memo(({ data }) => {
  console.log('Rendered');
  return <div>{data.value}</div>;
});

// 父组件
const Parent = () => {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <MyComponent data={{ value: count }} />
    </div>
  );
};

📌 问题:每次 Parent 重新渲染时,data={{ value: count }} 都会创建新的对象,导致 MyComponent 重新渲染,React.memo 在这里不起作用。
优化方案:使用 useMemo 保持 data 的稳定性:

const data = useMemo(() => ({ value: count }), [count]);

2️⃣ 组件内部状态变化

如果组件内部有 useState,并且 state 变化会导致组件重新渲染,那么 React.memo 也不会阻止它的重新渲染。

🔴 示例

const Counter = React.memo(() => {
  const [count, setCount] = useState(0);
  console.log('Rendered Counter');
  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
});

📌 问题:即使 CounterReact.memo 包裹,每次点击 buttonstate 发生变化,组件仍然会重新渲染,React.memo 在这里没有任何优化作用。

3️⃣ 组件渲染代价低

如果组件本身渲染开销很小(例如只渲染一个简单的 div),使用 React.memo 反而可能降低性能。因为 React.memo 需要额外进行 props 对比,这对小组件来说得不偿失。

🔴 示例

const SimpleComponent = React.memo(({ text }) => <div>{text}</div>);

📌 问题:组件本身只是渲染一个 div,不管是否用 React.memo,性能影响都微乎其微。此时 避免使用 React.memo

4️⃣ 子组件依赖于 context

如果组件通过 useContext 访问 context 值,并且 context 发生变化,React.memo 也无法阻止重新渲染。

🔴 示例

const ThemeContext = React.createContext();

const ThemedComponent = React.memo(() => {
  const theme = useContext(ThemeContext);
  return <div style={{ color: theme.color }}>Hello</div>;
});

📌 问题:如果 ThemeContextvalue 发生变化,ThemedComponent 仍然会重新渲染,React.memo 无法优化这种情况。

优化方案

  • context 提供的 valueuseMemo 包裹,减少不必要的 context 变化。
  • 使用 context 拆分策略,避免整个 context 变化时所有组件都重新渲染。

5️⃣ React.memo 不能阻止 useEffect 的执行

即使 React.memo 阻止了组件的重新渲染,但如果组件内部有 useEffect,且 useEffect 依赖的 props 发生变化,那么 useEffect 仍然会执行。

🔴 示例

const MyComponent = React.memo(({ count }) => {
  useEffect(() => {
    console.log('Effect ran');
  }, [count]);

  return <div>{count}</div>;
});

📌 问题:当 count 变化时,useEffect 仍然会运行,即使 React.memo 阻止了不必要的重新渲染,useEffect 也不会受到影响。

✅ 结论:何时不使用 React.memo

🚫 不适用的情况

  1. props 变化频繁,React.memo 仍然会导致重新渲染(如传递新的对象、数组、函数)。
  2. 组件内部有 useState,状态变化仍然会触发渲染。
  3. 组件渲染开销很低,React.memo 反而会增加性能损耗。
  4. 组件依赖 useContext,context 变化仍然会导致重新渲染。
  5. useEffect 依赖的 props 发生变化时,useEffect 仍然会执行,即使 React.memo 阻止了渲染。

适用的情况

  • 组件 性能开销较高(例如包含复杂计算、图表、列表等)。
  • 组件 props 很少变化,并且 props稳定的(如 useMemo 处理过的值)。
  • 组件是 纯 UI 组件,不依赖 contextstate

📌 总结

React.memo 并不是 万能优化工具,如果组件本身渲染很快、props 变化频繁,或者 context 发生变化,React.memo 可能不会带来任何性能提升,甚至会增加额外的计算开销。在使用它之前,务必 分析组件的实际性能瓶颈,而不是盲目地对所有组件使用 React.memo。 🚀