React组件优化:选中项时仅重渲染目标子组件
React选中单个Item时所有组件重渲染的解决方案
问题根源
你的代码里有三个核心问题导致所有Item都触发重渲染:
- MemoizedItem定义位置错误:把
MemoizedItem = memo(Item)放在了App组件内部,每次App状态更新(selected变化)都会重新创建这个组件,memo的缓存完全失效。 - 事件函数未缓存:
selectHandler没有用useCallback缓存,每次App渲染都会生成新的函数实例,所有Item接收的selectHandlerprops都会变化,memo浅比较判定props更新,触发重渲染。 - props传递冗余:给每个Item传了整个
selected数组,每次选中/取消操作都会生成新的数组引用,所有Item的selectedprops都发生变化,必然全部重渲染。
修复后的完整代码
import { memo, useState, useCallback } from "react"; const items = Array(100) .fill(null) .map((item, index) => { return { ...item, id: crypto.randomUUID(), name: `hello - ${index + 1}` }; }); type PropsItem = { data: { id: string; name: string }; isSelected: boolean; selectHandler: (isIncluded: boolean, id: string) => void; }; const Item = ({ data, isSelected, selectHandler }: PropsItem) => { return ( <div className="cursor-pointer min-w-[170px] text-center p-2"> {isSelected ? ( <s className="text-2xl" onClick={() => selectHandler(true, data.id)}> {data.name} </s> ) : ( <p className="text-2xl" onClick={() => selectHandler(false, data.id)}> {data.name} </p> )} </div> ); }; // 把MemoizedItem移到组件外部,确保只创建一次 const MemoizedItem = memo(Item); const App = () => { const [selected, setSelected] = useState<string[]>([]); // 用useCallback缓存事件函数,避免每次渲染生成新实例 const selectHandler = useCallback((isIncluded: boolean, id: string) => { if (isIncluded) { setSelected(prev => prev.filter(idx => idx !== id)); } else { setSelected(prev => [...prev, id]); } }, []); // 依赖为空,因为用了函数式更新,不需要依赖selected return ( <div className="flex flex-col gap-5 items-center justify-center py-10"> {items.map(item => ( <MemoizedItem key={item.id} data={item} // 只传递当前Item的选中状态布尔值,而非整个数组 isSelected={selected.includes(item.id)} selectHandler={selectHandler} /> ))} </div> ); }; export default App;
关键修复点说明
- MemoizedItem移到外部:保证组件实例唯一,memo的缓存逻辑能正常工作。
- useCallback缓存事件函数:让所有Item接收的
selectHandler引用始终一致,不会因为App渲染触发不必要的重渲染。 - 传递布尔值而非数组:只有选中状态变化的Item,其
isSelectedprops才会改变,其他Item的props完全不变,memo会跳过这些组件的重渲染。
内容的提问来源于stack exchange,提问作者Mario Podolinský
相关产品推荐
相关产品推荐

