1

我正在尝试专门用于响应钩子useReduce,为此我正在制作一个todoList示例,在该示例中,我想使用一个 reduce 来管理诸如添加、编辑、更新、删除和更改任务的完成状态等操作的状态和在另一个减少管理过滤器中,我可以列出所有todos或仅列出已完成和未完成的过滤器。

是否可以使用 useReducer 钩子通过多个 reducer 来管理状态?

现在,我不得不混合减速器,具有以下逻辑

import React, { useReducer, useState } from "react";
import uuid from "uuid/v4";

import Form from "../Form/Form";
import List from "../List/List";
import Filter from "../Filter/Filter";

const todoReducer = (state, action) => {
  switch (action.type) {
    case "ADD_TODO":
      return applyAddTodo(state, action);
    case "DELETE_TODO":
      return applyDeleteTodo(state, action);
    case "EDIT_TODO":
      return applyEditTodo(state, action);
    case "CANCEL_EDIT_TODO":
      return applyCancelEditTodo(state, action);
    case "UPDATE_TODO":
      return applyUpdateTodo(state, action);
    case "TOGGLE_COMPLETED_TODO":
      return applyToggleCompletedTodo(state, action);
    case "COMPLETED": // <- from here this should be in another reducer
      return applyFilterCompleted(state);
    case "UN_COMPLETED":
      return applyFilterUncompleted(state);
    case "ALL":
    default:
      return [...state];
  }
};

const todoFilter = (state, action) => {
  switch (action.type) {
    case "COMPLETED":
      return applyFilterCompleted(state, action);
    case "UN_COMPLETED":
      return applyFilterUncompleted(state, action);
    case "ALL":
    default:
      return [...state];
  }
};

const applyAddTodo = (state, action) => [
  ...state,
  { id: uuid(), task: action.payload.task, completed: false, isEditing: false }
];

const applyDeleteTodo = (state, action) =>
  state.filter(todo => todo.id !== action.payload.id);

const applyEditTodo = (state, action) =>
  state.map(todo =>
    todo.id === action.payload.id ? { ...todo, isEditing: true } : { ...todo }
  );

const applyCancelEditTodo = (state, action) =>
  state.map(todo =>
    todo.id === action.payload.id ? { ...todo, isEditing: false } : { ...todo }
  );

const applyUpdateTodo = (state, action) =>
  state.map(todo =>
    todo.id === action.payload.id
      ? { ...todo, task: action.payload.task, isEditing: false }
      : { ...todo }
  );

const applyToggleCompletedTodo = (state, action) =>
  state.map(todo =>
    todo.id === action.payload.id
      ? { ...todo, completed: !todo.completed }
      : { ...todo }
  );

const applyFilterCompleted = state => state.filter(todo => todo.completed);

const applyFilterUncompleted = state => state.filter(todo => !todo.completed);

const INITIAL_STATE = [
  {
    id: uuid(),
    task: "Learn react",
    dateCreated: Date.now(),
    completed: false,
    isEditing: false
  },
  {
    id: uuid(),
    task: "Learn react hooks",
    dateCreated: Date.now(),
    completed: true,
    isEditing: false
  }
];

const App = () => {
  const [state, dispatch] = useReducer(todoReducer, INITIAL_STATE);
  const [filter, setFilter] = useState("ALL");

  const addTodoHandler = task =>
    dispatch({ type: "ADD_TODO", payload: { task } });

  const editTodoHandler = id =>
    dispatch({ type: "EDIT_TODO", payload: { id } });

  const updateTodoHandler = (id, task) =>
    dispatch({ type: "UPDATE_TODO", payload: { id, task } });

  const cancelEditTodoHandler = id =>
    dispatch({ type: "CANCEL_EDIT_TODO", payload: { id } });

  const deleteTodoHandler = id =>
    dispatch({ type: "DELETE_TODO", payload: { id } });

  const toggleCompletedTodoHandler = id =>
    dispatch({ type: "TOGGLE_COMPLETED_TODO", payload: { id } });

  const filterHandler = filter => setFilter(filter);

  return (
    <div>
      <Form onAddTodo={addTodoHandler} />
      {state.length > 0 && (
        <div>
          <List
            todos={todoFilter(state, { type: filter })}
            onEditTodo={editTodoHandler}
            onUpdateTodo={updateTodoHandler}
            onCancelEditTodo={cancelEditTodoHandler}
            onDeleteTodo={deleteTodoHandler}
            onToggleCompletedTodo={toggleCompletedTodoHandler}
          />
          <Filter onFilter={filterHandler} />
        </div>
      )}
    </div>
  );
};

export default App;

现在reducetodoFilter我用它作为一个助手来列出todos

更新 1

我得到了这个解决方案

Todo减速机

const todoReducer = (state, action) => {
  switch (action.type) {
    case "ADD_TODO":
      return applyAddTodo(state, action);
    case "DELETE_TODO":
      return applyDeleteTodo(state, action);
    case "EDIT_TODO":
      return applyEditTodo(state, action);
    case "CANCEL_EDIT_TODO":
      return applyCancelEditTodo(state, action);
    case "UPDATE_TODO":
      return applyUpdateTodo(state, action);
    case "TOGGLE_COMPLETED_TODO":
      return applyToggleCompletedTodo(state, action);
    default:
      return state;
  }
};

减滤器

const filterReducer = (state, action) => {
  switch (action.type) {
    case "COMPLETED":
      return applyFilterCompleted(state, action);
    case "UN_COMPLETED":
      return applyFilterUncompleted(state, action);
    case "ALL":
    default:
      return [...state];
  }
};

主减速机

const reducer = (state, action) => {
  switch (action.type) {
    case "ADD_TODO":
    case "DELETE_TODO":
    case "EDIT_TODO":
    case "UPDATE_TODO":
    case "CANCEL_EDIT_TODO":
    case "TOGGLE_COMPLETED_TODO":
      return todoReducer(state, action);
    case "COMPLETED":
    case "UN_COMPLETED":
    case "ALL":
      return filterReducer(state, action);
    default:
      throw new Error();
  }
};

这可行,但我不喜欢它,因为必须在主减速器和辅助减速器中重复动作类型,最终某些动作类型将被省略,应用程序将失败。

有更聪明的解决方案吗?

感谢您的意见

4

0 回答 0