是否可以使用多个带有React useReducer钩子的reducer来管理状态?

时间:2019-12-03 21:45:43

标签: javascript reactjs react-hooks use-reducer

我正试图习惯于对钩子useReduce做出反应,为此,我正在制作一个todoList示例,其中我想使用一个reduce来管理诸如添加,编辑,更新,删除和更改任务的完成状态,并在另一个reduce管理过滤器中,该过滤器使我可以列出所有todos或仅列出已完成和未完成。

是否可以使用useReducer钩子通过多个减少器管理状态?

现在,我不得不混合使用减速器,其逻辑如下

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;

现在,约简todoFilter我将其用作列出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();
  }
};

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

有没有更聪明的解决方案?

感谢您的评论

0 个答案:

没有答案