Список задач с использованием useReducer и MongoDB — обновление БД после действия Reducer?

#javascript #node.js #reactjs #mongodb #use-reducer

#javascript #node.js #reactjs #mongodb #использование-reducer

Вопрос:

Я попытался подключить свой Todolist к MongoDB для хранения моих данных. Поскольку не рекомендуется извлекать и обновлять данные внутри редуктора, я немного запутался в том, где обновлять БД.

Я думаю, что всякий раз, когда я меняю список с помощью действия, мне нужно будет заменить весь список в БД, что мне не кажется эффективным. Но когда я обновляю только измененный элемент в БД, я не вижу причин использовать useReducer.

Может кто-нибудь помочь мне, как мне продолжить? :/

(Этот список задач использовал useStates и MongoDB до того, как я попытался использовать useReducer, поэтому маршруты и APIhelper включают другие функции)

App.js:

 import React, { useState, useEffect, useReducer } from "react";
import APIHelper from "./APIHelper.js";
import Todo from "./components/Todo";
import "./index.css";

export const ACTIONS = {
  ADD_TODO: "add-todo",
  TOGGLE_TODO: "toggle-todo",
  DELETE_TODO: "delete-todo",
  SET_TODO: "set-todos",
};

const reducer = (state, action) => {
  switch (action.type) {
    case ACTIONS.SET_TODOS: {
      return Object.assign({}, state.todos, {
        todos: action.payload.todos,
      });
    }

    case ACTIONS.ADD_TODO:
      return [...state.todos, newTodo(action.payload.task)];

    case ACTIONS.TOGGLE_TODO:
      return state.todos.map((todo) => {
        if (todo._id === action.payload.id) {
          return { ...todo, completed: !todo.completed };
        }
        return todo;
      });

    case ACTIONS.DELETE_TODO:
      return state.todos.filter((todo) => todo._id !== action.payload.id);
    default:
      return state.todos;
  }
};

const newTodo = (task) => {
  return { _id: Date.now(), task: task, completed: false };
};

export const setTodos = (todos) => {
  return {
    type: ACTIONS.SET_TODOS,
    payload: {
      todos,
    },
  };
};

const App = () => {
  const initialState = {
    todos: [],
  };

  const [state, dispatch] = useReducer(reducer, initialState);
  const [task, setTask] = useState("");

  useEffect(async () => {
    const fetchTodoAndSetTodo = async () => {
      const todos = await APIHelper.getAllTodos();
      return todos;
    };
    const todos = await fetchTodoAndSetTodo();
    //console.log(todos);
    dispatch(setTodos(todos));
  }, []);

  const handleSubmit = (e) => {
    e.preventDefault();
    dispatch({ type: ACTIONS.ADD_TODO, payload: { task: task } });
    setTask("");
  };

  return (
    <div>
      {console.log(state.todos)}
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={task}
          onChange={(e) => setTask(e.target.value)}
        />
      </form>
      {state.todos amp;amp;
        state.todos.map((todos) => {
          return <Todo key={todos._id} todo={todos} dispatch={dispatch} />;
        })}
        {//APIHelper.updateTodo(state.todos)}
    </div>
  );
};

export default App;
  

Todo.js:

 import React from "react";
import { ACTIONS } from "../App";

const Todo = ({ todo, dispatch }) => {
  return (
    <div>
      <span style={{ color: todo.complete ? "#AAA" : "#000" }}>
        {todo.task}
      </span>
      <button
        onClick={() =>
          dispatch({ type: ACTIONS.TOGGLE_TODO, payload: { id: todo.id } })
        }
      >
        Toggle
      </button>
      <button
        onClick={() =>
          dispatch({ type: ACTIONS.DELETE_TODO, payload: { id: todo.id } })
        }
      >
        Delete
      </button>
    </div>
  );
};

export default Todo;
  

APIHelper.js:

 import axios from "axios";

const API_URL = "http://localhost:8080/todos/";

const createTodo = async (task) => {
  const { data: newTodo } = await axios.post(API_URL, {
    task,
  });
  return newTodo;
};

const deleteTodo = async (id) => {
  const message = await axios.delete(`${API_URL}${id}`);
  return message;
};

const updateTodo = async (payload) => {
  const { data: newTodo } = await axios.put(`${API_URL}`, payload);
  return newTodo;
};

const getAllTodos = async () => {
  const { data: todos } = await axios.get(API_URL);
  return todos;
};

export default { createTodo, deleteTodo, updateTodo, getAllTodos };
  

routes.js:

 const db = require("./db.js");

const routes = express.Router();

const success = (res, payload) => {
  return res.status(200).json(payload);
};

routes.get("/", async (req, res, next) => {
  try {
    const todos = await db.Todo.find({}, "_id task completed");
    return success(res, todos);
  } catch (err) {
    next({ status: 400, message: "failed to get todos" });
  }
});

routes.post("/", async (req, res, next) => {
  try {
    const todo = await db.Todo.create(req.body);
    return success(res, todo);
  } catch (err) {
    next({ status: 400, message: "failes to create todo" });
  }
});

routes.put("/", async (req, res, next) => {
  try {
    const todo = await db.Todo.findByIdAndUpdate(req.params.id, req.body, {
      new: true,
    });
    return success(res, todo);
  } catch (err) {
    next({ status: 400, message: "failed to update todo" });
  }
});

routes.delete("/:id", async (req, res, next) => {
  try {
    await db.Todo.findByIdAndRemove(req.params.id);
    return success(res, "todo deleted");
  } catch (err) {
    next({ status: 400, message: "failed to delete todo" });
  }
});

routes.use((err, req, res, next) => {
  return res.status(err.status || 400).json({
    status: err.status || 400,
    message: err.message || "there was an error processing request",
  });
});

module.exports = routes;
```
  

Комментарии:

1. Обновление БД должно обрабатываться промежуточным программным обеспечением, которое перехватывает действия, выполняет асинхронные операции и отправляет новое действие по завершении задания. Например: кнопка отправляет действие «ADD_TODO», промежуточное программное обеспечение перехватывает его и пытается обновить базу данных, затем отправляет новое действие (например, «ADD_TODO_SUCCESS» или «ADD_TODO_FAILURE», в зависимости от результата операции), наконец, редуктор перехватывает действие, отправленное промежуточным программным обеспечением, и обновляетсостояние в соответствии с его полезной нагрузкой. [… продолжить …]

2. В этой статье показан способ повторить этот сценарий, используя только react: medium.com/@rossitrile93 /…