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

React Router+Redux中新增任务同步至所有项目的问题修复问询

问题:Redux中新增任务被添加到所有项目的状态中

在Redux状态中新增任务时,该任务会被添加到所有项目的状态中。需要修复此问题,确保每个项目拥有独立的任务状态。相关代码如下:


App.ts

const router = createBrowserRouter([
  {
    path: '/',
    element: <App/>,
  },
  {
    path: 'project/:projectId',
    element: <ProjectItems/>
  }
])

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

root.render(
  <Provider store={store}>
    <RouterProvider router={router}/>
  </Provider>
);

ProjectItems.tsx

const ProjectItems = () => {
    const { projectId } = useParams();

    const tasks = useAppSelector(state => state.task);
    const dispatch = useAppDispatch();

    useEffect(() => {
        localStorage.setItem('tasks', JSON.stringify(tasks))
    }, [tasks]);

    const addNewTask = () => {
        const newTask = {
            id: idGenerator(),
            title: prompt('')
        }
        dispatch(addTask({projectId, newTask}));
    }

    return (
        <div className={styles.Main}>
                <button onClick={addNewTask}></button>
        </div>
    )
}

export default ProjectItems;

Project.tsx

(此处渲染所有项目并为其添加链接)

interface IProject {
    id: string,
    title: string | null,
}

const Project: FC<IProject> = ({title, id}) => {
    const dispatch = useAppDispatch();

    const handleDeleteProject = () => {
        dispatch(deleteProject({id}));    
    }

    return (
        <div className={styles.Main}>
            <Link to={`project/${id}`}>
                <div className={styles.MainWrapper}>
                    {title}
                </div>
            </Link>
            <button onClick={handleDeleteProject}>Удалить</button>
        </div>  
    )
}

export default Project;

taskReducer.tsx

export enum TaskActions {
    ADD_TASK = 'ADD_TASK'
}

interface ITaskItem {
        id: string,
        title: string | null,
}

interface ITaskList {
    projectId: {
        tasks: ITaskItem[],
    }
}

interface IPayload {
    type: string,
    payload: {
        projectId: string,
        newTask: ITaskItem,
    },
}

const data = JSON.parse(localStorage.getItem('tasks') || '[]');

const initialState: ITaskList = {
        projectId: {
            tasks: data
        }
}

export const taskReducer = (state = initialState, action: IPayload) => {
    switch(action.type) {
        case TaskActions.ADD_TASK: {
            const { projectId, newTask } = action.payload;
            const newAddTasks = state.projectId.tasks;
            newAddTasks.push(newTask)
            return {
                ...state,
                [projectId]: {
                    ...state.projectId,
                    tasks: newAddTasks
                }
            }
        }
        default: return state;
    }
} 

actionTask.tsx

import { TaskActions } from "../reducers/taskReducer"


export const addTask = (payload: any) => {     
    return {
        type: TaskActions.ADD_TASK,
        payload,
    }
}

修复方案

核心问题点

  1. 状态结构设计错误:原ITaskList接口使用固定的projectId属性,导致所有项目共享同一任务列表,应改为索引签名实现项目独立存储。
  2. 直接修改状态引用:原代码直接对state.projectId.tasks执行push操作,违反Redux不可变更新原则,导致状态污染。
  3. localStorage初始化不匹配:原代码将存储数据解析为数组,与新的对象结构不兼容。
  4. 组件中任务获取逻辑错误:ProjectItems中获取的是整个task状态,而非当前项目的任务列表。

修改后的代码

taskReducer.tsx

export enum TaskActions {
    ADD_TASK = 'ADD_TASK'
}

interface ITaskItem {
        id: string,
        title: string | null,
}

// 修改为索引签名,每个项目ID对应独立的任务列表
interface ITaskList {
    [projectId: string]: {
        tasks: ITaskItem[],
    }
}

interface IPayload {
    type: string,
    payload: {
        projectId: string,
        newTask: ITaskItem,
    },
}

// 初始化解析为对象,而非数组
const data = JSON.parse(localStorage.getItem('tasks') || '{}');

const initialState: ITaskList = data;

export const taskReducer = (state = initialState, action: IPayload) => {
    switch(action.type) {
        case TaskActions.ADD_TASK: {
            const { projectId, newTask } = action.payload;
            // 获取当前项目已有任务,无则为空数组
            const currentTasks = state[projectId]?.tasks || [];
            // 创建新数组添加任务,保持不可变性
            const updatedTasks = [...currentTasks, newTask];
            
            return {
                ...state,
                [projectId]: {
                    tasks: updatedTasks
                }
            }
        }
        default: return state;
    }
} 

ProjectItems.tsx

修改任务获取逻辑,只获取当前项目的任务:

// 替换原tasks获取行
const tasks = useAppSelector(state => state.task[projectId]?.tasks || []);

actionTask.tsx

明确payload类型,避免any:

import { TaskActions, ITaskItem } from "../reducers/taskReducer"

export const addTask = (payload: {projectId: string, newTask: ITaskItem}) => {     
    return {
        type: TaskActions.ADD_TASK,
        payload,
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 16:30:12