如何在Redux中修改对象属性?Redux Todo完成功能reducer问题
Got it, let's break down what's going wrong with your current reducer and fix it so it properly toggles the complete status of the correct todo item.
The Problem with Your Current Reducer
Your current code is trying to modify the entire chores object directly, which doesn't work for arrays in Redux—we need to target individual items while keeping state immutability. Also, the return structure is incorrect: you're returning { ...state.chores, chore } instead of a new state object containing the updated chores array.
Correct Approach
We need to:
- Iterate over the
choresarray to find the todo matching the one in your action. - For the matching todo, create a new object with the toggled
completevalue. - Leave all other todos unchanged.
- Return a new state object with the updated
choresarray.
Updated Code
First, tweak your action creator (optional but aligned with Redux conventions)
Renaming data to payload is a common Redux practice, but we'll keep the core logic intact:
export const completeTodo = (todo) => ({ type: 'COMPLETE_TODO', payload: todo })
Now the Fixed Reducer
const initialState = { chores: [{name: 'cleaning', complete: false}] }; const todoReducer = (state = initialState, action) => { switch(action.type) { case 'COMPLETE_TODO': // Map over chores to create a new array (avoids mutating original state) const updatedChores = state.chores.map(chore => { // Check if this is the todo we need to update if (chore.name === action.payload.name) { // Return a new object with toggled complete status return { ...chore, complete: !chore.complete }; } // Return the original chore if it's not the target return chore; }); // Return a new state object with the updated chores array return { ...state, chores: updatedChores }; // Add other action cases (like ADD_TODO) here default: return state; } };
Why This Works
map()creates a brand new array, so we never mutate the original state (a critical Redux rule).- We only modify the specific todo that matches the action's payload, leaving all other todos untouched.
- We return a new state object preserving existing properties (so your state stays consistent if you add more features later).
Pro Tip: Use Unique IDs for Reliability
If you ever have todos with duplicate names, using a unique id will prevent accidental updates. Here's how to adjust:
// Initial state with unique IDs const initialState = { chores: [{id: 1, name: 'cleaning', complete: false}] }; // Updated action creator (pass just the ID) export const completeTodo = (todoId) => ({ type: 'COMPLETE_TODO', payload: todoId }); // Updated reducer case case 'COMPLETE_TODO': const updatedChores = state.chores.map(chore => { if (chore.id === action.payload) { return { ...chore, complete: !chore.complete }; } return chore; }); return { ...state, chores: updatedChores };
内容的提问来源于stack exchange,提问作者The Walrus

