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

Redux中修改列表项时如何仅渲染变更项?

解决Redux Todo列表仅修改项重渲染的问题

你遇到的问题核心是组件重渲染触发条件没控制好,虽然用了memo,但因为props传递的内容不稳定,或者组件依赖的状态范围太大,导致整个列表都跟着重渲染。以下是具体的解决思路和代码修改方案:

问题根源分析

  1. List组件的todoList引用变化:每次修改todo的状态,Redux Toolkit会生成新的数组引用(immer结构共享的特性),导致List组件必然重渲染。
  2. TodoItem的props不稳定:如果传递的setDone是每次渲染都生成的新函数,或者todo对象虽然没修改但因为父组件重渲染被重新传递,memo的浅比较会认为props变化,触发所有TodoItem重渲染。

解决方案一:让TodoItem独立获取自身数据(推荐)

让List只传递todo的id给TodoItem,TodoItem内部通过useSelector根据id获取对应的数据,这样List的重渲染不会影响未修改的TodoItem,只有目标TodoItem会因为数据变化重渲染。

修改TodoItem组件

import { useDispatch, useSelector } from 'react-redux';
import { setDone } from './todoSlice'; // 导入你的action

function TodoItem({ id }: { id: string }) {
  // 只获取当前id对应的todo
  const todo = useSelector((state: RootState) => state.todo.find(item => item.id === id));
  const dispatch = useDispatch();

  if (!todo) return null;

  return (
    <Row justify='space-between'>
      <Checkbox 
        checked={todo.done} 
        onChange={(e) => dispatch(setDone([id, e.target.checked]))}
      >
        <span style={todo.done ? { textDecoration: 'line-through' } : {}}>
          {todo.todo}
        </span>
      </Checkbox>
    </Row>
  );
}

export default memo(TodoItem);

修改List组件

function List() {
  const todoList = useSelector((state: RootState) => state.todo);
  
  return (
    <>
      {todoList.map(todo => (
        <TodoItem key={todo.id} id={todo.id} />               
      ))}     
    </>  
  );
}

export default memo(List); // 这个memo可以考虑去掉,因为List渲染成本极低

解决方案二:稳定传递的props(如果坚持传递todo和setDone)

如果不想改变数据获取方式,需要保证传递给TodoItem的props引用稳定:

  1. 用useCallback包裹setDone函数:在传递setDone的父组件中,用useCallback确保函数引用不变。
  2. 确保未修改的todo对象引用不变:RTK的immer已经保证了这一点,只要reducer写法正确,未修改的todo会保持原引用。

父组件中处理setDone

import { useDispatch, useCallback } from 'react-redux';
import { setDone } from './todoSlice';

function ParentComponent() {
  const dispatch = useDispatch();
  // 用useCallback稳定函数引用
  const handleSetDone = useCallback((id: string, done: boolean) => {
    dispatch(setDone([id, done]));
  }, [dispatch]);

  return <List setDone={handleSetDone} />;
}

List组件修正(原代码中的props.todoList是笔误,应该用自己获取的todoList)

function List({ setDone }: { setDone: (id: string, done: boolean) => void }) {
  const todoList = useSelector((state: RootState) => state.todo);
  
  return (
    <>
      {todoList.map(todo => (
        <TodoItem key={todo.id} todo={todo} setDone={setDone} />               
      ))}     
    </>  
  );
}

export default memo(List);

验证效果

修改后,点击某条todo的复选框,只有该TodoItem会重渲染,其他项不会有渲染触发。可以通过React DevTools的"Highlight Updates"功能来验证。

内容的提问来源于stack exchange,提问作者mukamuka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 04:16:09