Redux中dispatch changeStatus action组件未重新渲染,dispatch removeTask action正常的问题排查
completeTask Action Isn't Triggering Component Re-renders Hey there! Let's figure out why your component isn't updating when you dispatch the completeTask action, even though removeTask seems to work. I've spotted two key issues in your code that are causing this:
1. You're Mutating the Original Redux State (A Big No-No!)
Redux requires immutable state updates—you can't modify the original state directly. Your current reducer is mutating the existing tasks array instead of creating new copies, which tricks Redux into thinking nothing changed (it uses shallow comparison to detect updates; if the array reference stays the same, it skips re-renders).
Here's what's wrong in your reducer:
- In
addTask,let list = state.taskscreates a reference to the original array, thenlist.push(...)modifies it directly. - In
completeTask, you're updatinglist[index].statuson the original array's item without creating a new object. - Even
removeTaskuseslist.splice(...), which mutates the original array (the fact that it works sometimes is just a coincidence, not correct behavior).
Fix the Reducer to Use Immutable Updates
Rewrite your reducer to return new arrays/objects every time you make a change:
const HandleTaskReducer = (state = initializeState, action) => { switch (action.type) { case addTask: { // Create a new array with the new task appended const newTasks = [...state.tasks, action.payload]; localStorage.setItem('todos', JSON.stringify(newTasks)); return { ...state, tasks: newTasks }; } case completeTask: { // Map to a new array, and create a new object for the updated task const newTasks = state.tasks.map(task => task.id === action.payload ? { ...task, status: true } : task ); localStorage.setItem('todos', JSON.stringify(newTasks)); return { ...state, tasks: newTasks }; } case removeTask: { // Filter to create a new array excluding the deleted task const newTasks = state.tasks.filter(task => task.id !== action.payload); localStorage.setItem('todos', JSON.stringify(newTasks)); return { ...state, tasks: newTasks }; } default: { return state; // No need to spread here if no changes were made } } }
2. Your ListTaskComponent is Using Stale Local State
In ListTaskComponent, you're copying the Redux state into a local useState variable, but your useEffect only runs once when the component mounts (thanks to the empty dependency array). When the Redux state updates, your component receives new props, but the local tasks state never gets updated—so you're always rendering the initial list of tasks.
Remove the Local State and Use Props Directly
You don't need local state here—just use the props provided by connect directly:
import React from 'react'; import TaskItemComponent from "./TaskItemComponent"; import {connect} from "react-redux"; const ListTaskComponent = props => { // Use the props directly instead of syncing to local state const taskList = props.taskState.tasks.map(value => <TaskItemComponent key={value.id.toString()} task={value} /> ); return ( <section id="wrap-task" className="mt-3"> {taskList} </section> ) } const mapStateToProps = state => { return { taskState: state.taskReducer, } } export default connect(mapStateToProps, null)(ListTaskComponent)
Why This Fixes the Problem
- By returning new arrays/objects in the reducer, Redux can detect the state change and trigger component re-renders correctly.
- Using props directly in
ListTaskComponentensures you always render the latest data from Redux, no need to manually sync local state.
Give these changes a try—your completeTask action should now trigger a re-render just like removeTask does!
内容的提问来源于stack exchange,提问作者Khả Nam

