React中map循环内避免使用inline function的最高效实现方案是什么
React map循环中避免内联函数的最高效实现方案
你给出的两种写法都有优化空间:第一种每次渲染会在循环中生成和列表长度一致的临时匿名函数,若子组件为纯组件还会触发不必要的重渲染;第二种写法存在过度优化的核心原因是就算用useCallback缓存了外层回调,子组件内部仍需生成绑定索引的函数,且如果没有配合memo包装子组件,依然避免不了全量重渲染的问题。
最优实现方案
核心思路是事件委托+DOM自定义属性传索引+memo包装子组件+useCallback缓存全局回调,完全避免循环中生成任何重复函数,同时最小化重渲染范围:
import { memo, useCallback, useState } from 'react'; // memo包装子组件,仅props发生变化时才会重渲染 const Item = memo(({ content, isActive, index }) => { return <div className={isActive ? 'active' : ''} data-item-id={index} > {content} </div> }) const SomeComponent = () => { const [activeIndex, setActiveIndex] = useState(null); // 全局仅生成一次回调,永远不会更新 const handleContainerClick = useCallback((e) => { // 从触发事件的DOM元素自定义属性中取索引,无需提前绑定 const targetIndex = Number(e.target.dataset.itemId); if (isNaN(targetIndex)) return; setActiveIndex(targetIndex); // 其他点击逻辑 console.log(targetIndex); }, []); return ( // 事件委托到父容器,全程只挂载1个监听函数 <div onClick={handleContainerClick}> {[...Array(100)].map((_, index) => ( <Item key={index} index={index} content={`Click me ${index}`} isActive={activeIndex === index} /> ))} </div> ) }
优化点匹配说明
- 避免循环重复创建函数:整个方案全局仅生成1个点击回调,循环过程中没有任何函数创建逻辑,完全消除重复函数生成的开销
- 避免全量重渲染:点击操作仅会修改
activeIndex,只有旧的选中项和新的选中项两个子组件的isActive属性会变化,剩余子组件因为memo的浅比较会直接跳过渲染 - 垃圾回收:没有生成任何临时匿名函数,GC压力几乎可以忽略
次优方案(不适合用事件委托的场景)
如果你的业务场景中子组件层级深、自定义属性传递麻烦,可以选择给memo子组件传递索引和缓存的回调,子组件内部再用useCallback绑定索引:
const Item = memo(({ index, onClick, content, isActive }) => { // 仅当index或onClick变化时才会生成新回调,onClick被外层useCallback缓存后只会在index变化时更新 const handleClick = useCallback(() => onClick(index), [index, onClick]); return <div onClick={handleClick} className={isActive ? 'active' : ''}>{content}</div> })
该方案的性能略低于事件委托方案,但远优于你给出的两种写法。
内容的提问来源于stack exchange,提问作者DraganS
相关产品推荐
相关产品推荐

