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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:40:34