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

Reducer接收新顺序数组Payload后状态未更新问题求助

Hey there, let's figure out why your state isn't updating even though the payload looks correct when using React Beautiful DnD!

Common Causes & Fixes

1. You're Using Indexes as Keys for Draggable Items

React relies on stable, unique keys to correctly diff and re-render components. If you're using array indexes as keys for your todo items, rearranging the array will change the keys, which can break React's re-rendering logic and make it seem like the state didn't update.

Bad Practice:

{todos.map((todo, index) => (
  <Draggable key={index} draggableId={index.toString()}>
    {/* Todo item content */}
  </Draggable>
))}

Fix:
Use a unique, stable ID from your todo objects instead:

{todos.map(todo => (
  <Draggable key={todo.id} draggableId={todo.id.toString()}>
    {/* Todo item content */}
  </Draggable>
))}

2. Verify Your Reducer is Returning a New State Reference

Even though your code looks correct, double-check that the new todos array has a different reference than the old one. Add logs to your reducer to confirm:

case "endDrag":
  console.log("Old todos reference:", state.todos);
  console.log("New payload reference:", action.payload);
  console.log("References are different?", state.todos !== action.payload);
  return { ...state, todos: action.payload };

If the log says References are different? false, your rearrange function isn't creating a new array. Double-check the function:

const rearrange = (array, source, destination) => {
  // Create a shallow copy of the original array
  const newArray = [...array];
  const movedItem = newArray.splice(source, 1)[0];
  newArray.splice(destination, 0, movedItem);
  return newArray;
};

This should always return a new array reference—if it's not, make sure you're not passing a mutated array into the function elsewhere.

3. Your Component Might Be Blocking Re-Renders with React.memo

If you wrapped your todo list component with React.memo, ensure the comparison function isn't incorrectly skipping re-renders. For example:

// Bad: This will skip re-renders even if todos array content changes (but reference is same)
const TodoList = React.memo(({ todos }) => { /* ... */ }, 
  (prev, next) => prev.todos === next.todos
);

Either remove the custom comparison function (let React do shallow comparison automatically) or update it to check array content if needed.

4. Ensure You're Using the Latest todos State in onDragEnd

If your onDragEnd handler is using a stale version of the todos state (from a closure), you might be dispatching an update based on old data. Make sure you're pulling the latest state directly from your context when handling the drag end:

const { todos, dispatch } = useContext(TodoContext);

const onDragEnd = (result) => {
  if (!result.destination) return;
  // Use the latest todos state here, not a stale value
  const newArray = rearrange(todos, result.source.index, result.destination.index);
  dispatch({ type: "endDrag", payload: newArray });
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:03:00