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
相关产品推荐
相关产品推荐

