javascript - 带有 useReducer 和 MongoDB 的待办事项列表 - 错误:“todo.map 不是函数”
问题描述
我尝试使用 nodejs 和 MongoDB 设置一个简单的 Todolist。
我还使用 useReducer 来简化所有操作并更好地理解它。
我不知道我哪里出错了,但我收到错误“todos.map 不是函数”。我想这与获取数据库列表有关,但我不确定:/
应用程序.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 = (todos, action) => {
switch (action.type) {
case ACTIONS.SET_TODOS: {
return Object.assign({}, todos, {
todos: action.payload.todos,
});
}
case ACTIONS.ADD_TODO:
return ([...todos, newTodo(action.payload.name)])
case ACTIONS.TOGGLE_TODO:
return todos.map(todo => {
if(todo.id === action.payload.id) {
return { ...todo, complete: !todo.complete}
}
return todo;
})
case ACTIONS.DELETE_TODO:
return todos.filter(todo => todo.id !== action.payload.id)
default:
return todos;
}
}
const newTodo = (name) => {
return { id: Date.now(), name: name, complete: false }
}
export const setTodos = (todos) => {
return {
type: ACTIONS.SET_TODOS,
payload: {
todos
},
};
};
const App = () => {
const initialState = {
todos: []
};
const [todos, dispatch] = useReducer(reducer, initialState);
const [name, setName] = 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: {name: name} })
setName('')
}
return (
<div>
{console.log(todos)};
<form onSubmit = {handleSubmit}>
<input type="text" value={name} onChange = {e => setName(e.target.value)}/>
</form>
{todos.map(todo => {
return <Todo key={todo.id} todo={todo} dispatch = {dispatch} />
})}
</div>
)
}
export default App;
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 (id, payload) => {
const { data: newTodo } = await axios.put(`${API_URL}${id}`, payload);
return newTodo;
};
const getAllTodos = async () => {
const { data: todos } = await axios.get(API_URL);
return todos;
};
export default { createTodo, deleteTodo, updateTodo, getAllTodos };
Todo.js:
import React from "react";
import {ACTIONS} from '../App'
const Todo = ({ todo, dispatch}) => {
return (
<div>
<span style = {{ color: todo.complete ? '#AAA' : '#000'}}>
{todo.name}
{console.log(todo.name)}
</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;
我希望有一个人可以帮助我:(
解决方案
在你的减速器中,你试图映射状态对象,但你应该映射todos
状态对象的数组:
case ACTIONS.TOGGLE_TODO:
// todos is actually the state object
return todos.map(todo => {
您应该:
1.重命名todos
为state
const reducer = (state, action) => {
switch (action.type) {
case ACTIONS.SET_TODOS: {
return {
...state,
todos: action.payload.todos,
};
}
case ACTIONS.ADD_TODO:
return {
...state,
todos: [...state.todos, newTodo(action.payload.name)],
};
case ACTIONS.TOGGLE_TODO:
return {
...state,
todos: state.todos.map((todo) => {
if (todo.id === action.payload.id) {
return { ...todo, complete: !todo.complete };
}
return todo;
}),
};
case ACTIONS.DELETE_TODO:
return {
...state,
todos: state.todos.filter((todo) => todo.id !== action.payload.id),
};
default:
return state;
}
};
或者...
2. 将您的状态对象更改为待办事项数组:
const initialState = [] // todos array
const reducer = (todos, action) => {
switch (action.type) {
case ACTIONS.SET_TODOS: {
return action.payload.todos;
}
case ACTIONS.ADD_TODO:
return [...todos, newTodo(action.payload.name)];
case ACTIONS.TOGGLE_TODO:
return todos.map((todo) => {
if (todo.id === action.payload.id) {
return { ...todo, complete: !todo.complete };
}
return todo;
});
case ACTIONS.DELETE_TODO:
todos.filter((todo) => todo.id !== action.payload.id);
default:
return todos;
}
};
推荐阅读
- html - 使用 UNION ALL 的查询不会写入 html
- java - Java/Android:如何使用 Adapter 类从 20 个对象的数组中随机生成 12 个对象到 GridView?
- xcode - 请解释 Xcode 内存调试器的内容
- c# - 如何简化 C# 中的大 if 语句?
- go - 如何循环遍历 UUID 项
- excel - Excel : Distribute Percentage evenly for a range of numbers
- hyperledger-fabric - orderer.common.broadcast ccd Error reading from 10.110.16.204:37291: rpc error: code = Canceled desc = context canceled
- javascript - JavaScript class did not function in asp.net
- javascript - 纯 HTML 标记的选择性呈现
- ios - Depth capture for iPhone X back camera not working