javascript 使用react-router更改redux中嵌套对象的状态

xtfmy6hx  于 2023-10-14  发布在  Java
关注(0)|答案(1)|浏览(125)

有一个问题,当我添加一个新的任务的状态,它被添加到所有项目的状态。我如何解决这个问题。每个项目都必须有自己的状态。
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,
    }
}
6za6bjd0

6za6bjd01#

问题

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

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

ADD_TASK reducer示例抓取state.projectId.tasks数组,并通过直接推入它来改变它。然后,它将这个变异的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
    }
  }
}

解决方案

更新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 任务列表(* 用于状态持久化目的 *),然后使用当前projectId路由路径参数访问 * 该 * 项目的tasks数组。

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>
  );
};

相关问题