我沿着TOP完成了完整的堆叠式课程,每一次练习都很顺利,所以我偏离了课程,构建了一个简单的todo应用程序来巩固我迄今为止获得的知识。所以我用react开发了前端,然后用nodeexpress开发了连接到mongoDB的后端。一切似乎都很好,但随后删除请求停止了工作——其他所有请求都正常工作,只有删除会导致错误。请求删除后,页面崩溃,但在数据库中,请求得到满足,注释被删除。因此,当我重新连接到节点服务器并刷新页面时,内容是最新的,一切似乎都能正常工作。
RESTclient表示删除请求运行良好。但在浏览器中,当我点击删除按钮时,大约一秒钟后应用程序崩溃,这显示在控制台中:
Notes.js:20 Uncaught TypeError: Cannot read properties of null (reading 'id')
at Notes.js:20:27
at Array.map (<anonymous>)
at b (Notes.js:19:16)
at xo (react-dom.production.min.js:167:137)
at Pi (react-dom.production.min.js:197:258)
at Eu (react-dom.production.min.js:292:88)
at bs (react-dom.production.min.js:280:389)
at gs (react-dom.production.min.js:280:320)
at vs (react-dom.production.min.js:280:180)
at ls (react-dom.production.min.js:271:88)
server.js:
require("dotenv").config();
const express = require("express");
const morgan = require("morgan");
const cors = require("cors");
const mongoose = require("mongoose");
const Note = require("./models/note");
const app = express();
app.use(express.static("build"));
app.use(express.json());
app.set("json spaces", 2);
app.use(cors());
app.use(morgan("tiny"));
/// DEFINE DEFAULT PORT //
const PORT = process.env.PORT;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
/// DEFINE BASIC ROUTES
app.get("/notes", (request, response, next) => {
Note.find({}).then((notes) => response.json(notes));
});
app.get("/notes/:id", (request, response, next) => {
Note.findById(request.params.id)
.then((note) => {
if (note) {
response.json(note);
} else {
response.status(404).end();
}
})
.catch((error) => next(error));
});
/// DELETE ///
app.delete("/notes/:id", (request, response, next) => {
Note.findByIdAndRemove(request.params.id)
.then((response) => response.status(204).end())
.catch((error) => next(error));
});
/// UPDATE ///
app.put("/notes/:id", (request, response, next) => {
const {content, done} = request.body
Note.findByIdAndUpdate(
request.params.id,
{content, done},
{new: true, runValidators: true, context: "query"},
)
.then(updatedNote => response.json(updatedNote))
.catch(error => next(error))
})
/// ADD ///
app.post("/notes", (request, response, next) => {
const body = request.body;
if (!body.content) {
return response.status(400).json({
error: "content missing",
});
}
const note = new Note({
content: body.content,
done: false,
});
note
.save()
.then((saved) => response.json(saved))
.catch((error) => next(error));
});
/// HANDLE UNDEFINED ROUTES ///
const unknownEndpoint = (request, response) => {
response.status(404).send({ error: "unknown endpoint" });
};
app.use(unknownEndpoint);
/// HANDLE ERRORS ///
const errorHandler = (error, request, response, next) => {
console.error(error.message);
if (error.name === "CastError") {
return response.status(400).send({ error: "malformatted id" });
} else if (error.name === "ValidationError") {
return response.status(400).json({ error: error.message });
}
next(error);
};
app.use(errorHandler);
前端,app.js:
import { useState, useEffect } from "react";
import css from "./App.css"
import Button from "./Button";
import Input from "./Input";
import noteService from "./services/NoteService";
import Notes from "./Notes";
function App() {
const [notes, setNotes] = useState([]);
const [newNote, setNewNote] = useState("");
useEffect(() => {
noteService.getAll().then((response) => {
setNotes(response);
});
}, []);
const handleInput = (event) => {
const content = event.target.value;
setNewNote(content);
};
const handleSubmit = (event) => {
event.preventDefault();
const note = { content: newNote, done: false };
noteService
.create(note)
.then((response) => setNotes(notes.concat(response)));
setNewNote("");
};
const handleDelete = (id) => {
noteService
.trash(id)
.then(setNotes(notes.filter((note) => note.id !== id)));
};
const toggleStatus = (id) => {
const note = notes.find((item) => item.id === id);
const updated = { ...note, done: !note.done };
noteService.update(id, updated).then((response) => {
setNotes(notes.map((note) => (note.id !== id ? note : response)));
});
};
const showDone = () => {
noteService.getAll().then((response) => {
setNotes(response.filter((note) => note.done));
});
};
const showUndone = () => {
noteService.getAll().then((response) => {
setNotes(response.filter((note) => !note.done));
});
};
const showAll = () => {
noteService.getAll().then((response) => {
setNotes(response);
});
};
return (
<div className="container">
<h1>TO_DO NOTES</h1>
<div className="header">
<Input action={handleInput} value={newNote} />
<Button text={"Add"} action={handleSubmit} />
</div>
<div>
<Button text="Show All" action={showAll} />
<Button text="Show Done" action={showDone} />
<Button text="Show Undone" action={showUndone} />
</div>
<Notes notes={notes} action={handleDelete} toggle={toggleStatus}/>
</div>
);
}
export default App;
Notes.js:
import Button from "./Button";
import css from "./Notes.css";
const Note = ({ item, action, toggle }) => {
return (
<li
onClick={() => toggle(item.id)}
className={item.done ? "done" : "undone"}
>
{item.content} <Button text="x" action={() => action(item.id)} />
</li>
);
};
const Notes = ({ notes, action, toggle }) => {
return (
<>
<ul>
{notes.map((item) => (
<Note key={item.id} item={item} action={action} toggle={toggle} />
))}
</ul>
</>
);
};
export default Notes;
NoteService.js:
import axios from "axios";
const baseUrl = "/notes";
const getAll = () => {
const request = axios.get(baseUrl);
return request.then((response) => response.data);
};
const create = (newObject) => {
const request = axios.post(baseUrl, newObject);
return request.then((response) => response.data);
};
const update = (id, newObject) => {
const request = axios.put(`${baseUrl}/${id}`, newObject);
return request.then((response) => response.data);
};
const trash = id => {
const request = axios.delete(`${baseUrl}/${id}`)
return request.then(result => result.data)
}
export default {
getAll,
create,
update,
trash,
};
我真的很感激你的帮助。我将这个项目与我的另一个项目进行了比较,这个项目结构相同,另一个正在运行,但这里无法找出问题所在。
在Notes组件内的Notes.js文件中,使用Notes.map进行迭代,将其更改为notes?.map
,然后查看是否有效。