#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 /…