当我向状态添加新任务时出现问题,它被添加到所有项目的状态. 我怎么才能解决这个问题呢?每个项目都有自己的状态是必要的.

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,
    }
}

推荐答案

Issue

按照您输入任务状态的方式,它都保存在一个"projectId"属性下.

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

ADD_TASK减速器表壳抓住state.projectId.tasks数组,并通过直接推入它来改变它.它then将这个变异的newAddTasks数组保存到单个项目的tasks数组中.

case TaskActions.ADD_TASK: {
  const { projectId, newTask } = action.payload;
  const newAddTasks = state.projectId.tasks;
  newAddTasks.push(newTask) // <-- mutation!!
  return {
    ...state,
    [projectId]: {
      ...state.projectId,
      tasks: newAddTasks // <-- copy of all tasks
    }
  }
}

Solution

更新taskReducer以正确计算初始状态并处理ADD_TASK操作.

interface ITaskList {
  [projectId: string]: {
    tasks: ITaskItem[];
  };
}

// Access existing persisted state or provide empty object initial value
const initialState = JSON.parse(String(localStorage.getItem("tasks"))) || {};

export const taskReducer = (
  state: ITaskList = initialState,
  action: IPayload
) => {
  switch (action.type) {
    case TaskActions.ADD_TASK: {
      const { projectId, newTask } = action.payload;

      return {
        ...state,
        [projectId]: {
          // Grab current tasks array or create new, then append new task
          tasks: (state[projectId]?.tasks ?? []).concat(newTask)
        }
      };
    }

    default:
      return state;
  }
};

应该更新ProjectItems组件以读取complete任务列表(for state persistence purposes you have there),然后使用当前的projectId路由路径参数访问that项目的tasksarray.

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

  const dispatch = useAppDispatch();

  // All tasks in state
  const allTasks = useAppSelector((state) => state.tasks);

  // This project's tasks
  const tasks = allTasks[projectId]?.tasks ?? [];

  useEffect(() => {
    // Persist all tasks state to localStorage
    localStorage.setItem("tasks", JSON.stringify(allTasks));
  }, [allTasks]);

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

  return (
    <div className={styles.Main}>
      <button onClick={addNewTask}>Add New Task</button>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>{task.title}</li>
        ))}
      </ul>
    </div>
  );
};

Edit clever-knuth-gxtx47

Javascript相关问答推荐

使用reaction创建可排序的表不起作用

为什么在获取回调内设置状态(不会)会导致无限循环?

如何访问react路由v6加载器函数中的查询参数/搜索参数

如何将连续的十六进制字符串拆分为以空间分隔的十六进制块,每个十六进制块包含32个二元组?

类型自定义lazy Promise. all

React 17与React 18中的不同setState行为

Chrome是否忽略WebAuthentication userVerification设置?""

如何找出摆线表面上y与x相交的地方?

如何从一个列表中创建一个2列的表?

如何粗体匹配的字母时输入搜索框使用javascript?

Promise Chain中的第二个useState不更新

无法检测卡片重叠状态的问题

我创建了一个创建对象的函数,我希望从该函数创建的对象具有唯一的键.我怎么能做到这一点?

当使用';字母而不是与';var#39;一起使用时,访问窗口为什么返回未定义的?

类构造函数不能在没有用With Router包装的情况下调用

为什么客户端没有收到来自服务器的响应消息?

为什么这个.add.group({})在教程中运行得很好,但在我的游戏中就不行了?

JS Animate()方法未按预期工作

如何使用画布在另一个内部绘制一个较小但相同的形状,同时保持恒定的边界厚度?

如何修复使用axios运行TSC index.ts时出现的错误?