React.memo传递函数props时失效,寻求解决方法
React.memo失效问题解决:避免列表项不必要重渲染
问题根源
React.memo通过浅比较props来决定是否重渲染组件,但你在父组件TaskManeger的list.map中,用箭头函数包裹传递给Task的handleDelete、handleFavorite等函数:
handleDelete={()=>deleteTask(itemList)} handleFavorite={()=>handleAddFavorite(itemList.id)}
父组件每次渲染时,这些箭头函数都会生成全新的函数引用,导致React.memo的浅比较认为props发生了变化,最终所有Task组件都会重渲染,不管其他props是否真的改变。
另外,你的状态更新函数(比如handleAddFavorite)依赖了list状态,父组件每次渲染时这些函数也会重新创建,进一步加剧了问题。
解决方案
1. 用useCallback缓存状态处理函数
使用React的useCallback钩子,让状态处理函数的引用保持稳定,只有当依赖项变化时才重新创建。同时改用函数式状态更新,避免依赖list状态:
修改TaskManeger中的函数:
import './TaskManeger.css' import {Task} from "../../components"; import React, {useState,useEffect,useCallback} from 'react' // 引入useCallback const TaskManeger = () => { // ... 其他状态保持不变 // 缓存handleAddFavorite,依赖为空数组 const handleAddFavorite = useCallback((id) => { setList(prevList => prevList.map(itemList => itemList.id === id ? { ...itemList, favorite: !itemList.favorite } : itemList )) }, []) // 缓存handleAddComplete const handleAddComplete = useCallback((id) => { setList(prevList => prevList.map(itemList => itemList.id === id ? { ...itemList, complete: !itemList.complete } : itemList )) }, []) // 缓存deleteTask const deleteTask = useCallback((item) => { setList(prevList => prevList.filter(i=> i.id !== item.id)) }, []) // ... 其他函数保持不变
2. 优化函数传递方式,避免创建新箭头函数
在Task组件中修改按钮的点击逻辑,让子组件自己传递所需参数,父组件直接传递缓存后的函数引用:
首先修改Task组件的按钮:
const Task = (props) => { return ( <div className='task'> <div className='task_title'> <h2>{props.title}</h2> <div className='task_settings' > {/* 子组件调用时传入id */} <button onClick={() => props.handleFavorite(props.id)}> <img src= {props.favorite?starFull:star} alt="" /> </button> <button onClick={() => props.handleComplete(props.id)}> <img src= {props.complete?verifyFull:verify} alt="" /> </button> {/* 子组件调用时传入当前item */} <button onClick={() => props.handleDelete(props)}> <img src={junk} alt="" /> </button> </div> </div> {/* ... 其他内容不变 */} </div> ) } // 确保Task组件用memo包裹后导出 export default memo(Task)
然后修改TaskManeger中map的Task组件传参:
{list.map( itemList =>( <Task key={itemList.id} title={itemList.title} description={itemList.description} date={itemList.date} handleDelete={deleteTask} // 直接传缓存后的函数 handleFavorite={handleAddFavorite} handleComplete={handleAddComplete} id={itemList.id} favorite={itemList.favorite} complete={itemList.complete} /> ))}
3. 检查Task组件的导出
确保Task组件最终导出的是被memo包裹的版本,这是React.memo生效的前提:
// Task组件末尾添加 export default memo(Task)
效果验证
完成以上修改后,只有当某个Task的title、favorite、complete等props真正变化时,该组件才会重渲染,其他未变化的列表项不会触发重渲染,React.memo就能正常发挥性能优化作用了。
内容的提问来源于stack exchange,提问作者user20544557
相关产品推荐
相关产品推荐

