You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何避免父组件colour状态变更时子组件批量重渲染?

问题描述

我有一系列可交互的Box组件,点击Box时会将其颜色改为父组件colour状态的值。当前实现下,当colour状态变更时,useCallback会生成新的changeColour函数并传递给每个Box,导致所有子组件重渲染。请问如何重构代码,避免colour状态变更时所有子组件都发生重渲染?

简化代码示例:

import React, { useState, useCallback } from "react";
import "./styles.css";

const Box = React.memo(({ c, i, handleClick }) => {
  return (
    <div
      className="box"
      style={{ background: c }}
      onClick={() => handleClick(i)}
    ></div>
  );
});

export default function App() {
  const COUNT_BOXES = 250;
  const [colour, setColour] = useState("#00ff00");
  const [boxes, setBoxes] = useState(Array(COUNT_BOXES).fill("#ff00ff"));

  const changeColour = useCallback(
    (i) => {
      setBoxes((prevBoxes) => {
        prevBoxes[i] = colour;
        return [...prevBoxes];
      });
    },
    [colour]
  );

  return (
    <div className="App">
      <input
        type="color"
        value={colour}
        onChange={(e) => setColour(e.target.value)}
      />
      Change colour
      <div className="wrapper">
        {boxes.map((c, i) => (
          <Box key={i} c={c} i={i} handleClick={changeColour} />
        ))}
      </div>
    </div>
  );
}
重构方案

核心是让changeColour函数的引用保持稳定,不随colour状态变化而更新,同时能获取到最新的colour值。具体实现如下:

import React, { useState, useCallback, useRef, useEffect } from "react";
import "./styles.css";

const Box = React.memo(({ c, i, handleClick }) => {
  return (
    <div
      className="box"
      style={{ background: c }}
      onClick={() => handleClick(i)}
    ></div>
  );
});

export default function App() {
  const COUNT_BOXES = 250;
  const [colour, setColour] = useState("#00ff00");
  const [boxes, setBoxes] = useState(Array(COUNT_BOXES).fill("#ff00ff"));
  // 用ref存储最新的colour值
  const colourRef = useRef(colour);

  // colour更新时同步ref的内容
  useEffect(() => {
    colourRef.current = colour;
  }, [colour]);

  // 函数不再依赖colour,引用保持稳定
  const changeColour = useCallback((i) => {
    setBoxes((prevBoxes) => {
      // 先复制原数组再修改,避免直接操作状态
      const newBoxes = [...prevBoxes];
      newBoxes[i] = colourRef.current;
      return newBoxes;
    });
  }, []);

  return (
    <div className="App">
      <input
        type="color"
        value={colour}
        onChange={(e) => setColour(e.target.value)}
      />
      Change colour
      <div className="wrapper">
        {boxes.map((c, i) => (
          <Box key={i} c={c} i={i} handleClick={changeColour} />
        ))}
      </div>
    </div>
  );
}

关键改动说明

  • 用useRef跟踪最新颜色:colourRef会始终保存colour的最新值,避免changeColour直接依赖colour状态。
  • 稳定函数引用:changeColour的useCallback依赖数组为空,函数引用不会随colour变化而更新,因此不会触发所有Box组件的重渲染。
  • 规范状态更新:修复原代码中直接修改prevBoxes的问题,先复制数组再修改,符合React状态不可变的原则。

这样,只有被点击的Box组件会因为c属性变化而重渲染,其余组件在colour变更时不会触发重渲染。

内容的提问来源于stack exchange,提问作者Abby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:15:35