Chúng ta xây gì
Sổ lưu bút: form trong React gửi tin lên server, server lưu và hiện cho mọi khách sau. Nhớ form Cấp 2 không có chỗ gửi? Hôm nay trả nợ.
Xem này: backend sổ lưu bút
Trong thư mục my-server, cài thêm một package:
npm install cors
Và sửa server.js:
const express = require("express");
const cors = require("cors");
const app = express();
app.use(cors()); // allow the frontend on a different port to ask questions
app.use(express.json()); // understand JSON in incoming requests
const messages = [
{ name: "Martin", text: "First message! Long live the guestbook. 📖" },
];
// GET – hand out messages
app.get("/api/messages", (request, response) => {
response.json(messages);
});
// POST – accept a new message
app.post("/api/messages", (request, response) => {
const { name, text } = request.body;
// Never trust input: check it on the server too!
if (!name || !text || name.length > 50 || text.length > 500) {
return response.status(400).json({ error: "Invalid message." });
}
messages.push({ name, text });
response.json({ saved: true });
});
app.listen(3900, () => {
console.log("Server running at http://localhost:3900");
});
Thứ mới:
cors()– frontend chạy cổng 3901, server 3900. Trình duyệt thường chặn yêu cầu “khác nguồn” (quy tắc CORS); đây là cách server cho phép.app.post(...)– endpoint POST đầu tiên! Dữ liệu form nằm trongrequest.body.- Kiểm tra trên server – frontend đã kiểm tra form, nhưng kẻ tấn công có thể bỏ qua form gửi thẳng. Quy tắc sắt: backend luôn kiểm tra, không tin frontend.
status(400)nghĩa là “yêu cầu sai.”
Xem này: frontend sổ lưu bút
Trong dự án React, tạo src/GuestBook.jsx:
import { useState, useEffect } from 'react';
function GuestBook() {
const [messages, setMessages] = useState([]);
const [name, setName] = useState("");
const [text, setText] = useState("");
// On first render: download the messages from the server
useEffect(() => {
fetch("http://localhost:3900/api/messages")
.then((response) => response.json())
.then((data) => setMessages(data));
}, []);
function submit(event) {
event.preventDefault();
fetch("http://localhost:3900/api/messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, text }),
})
.then((response) => response.json())
.then(() => {
setMessages([...messages, { name, text }]); // add it to the screen too
setName("");
setText("");
});
}
return (
<div>
<h2>Guestbook 📖</h2>
{messages.map((message, index) => (
<div className="card" key={index}>
<strong>{message.name}</strong>
<p>{message.text}</p>
</div>
))}
<form onSubmit={submit}>
<input
value={name}
onChange={(event) => setName(event.target.value)}
placeholder="Your name"
/>
<textarea
value={text}
onChange={(event) => setText(event.target.value)}
placeholder="Write a message..."
/>
<button type="submit">Send</button>
</form>
</div>
);
}
export default GuestBook;
Ba thứ React mới cuối:
useEffect(() => {...}, [])– “chạy một lần khi component hiện lần đầu.” Chỗ lý tưởng tải dữ liệu.fetchvớimethod: "POST"– gửi dữ liệu;JSON.stringifyđóng gói JSON.- Form nối state – ô đọc giá trị từ state (
value={name}) và ghi lại khi gõ (onChange). Form và state luôn đồng bộ.
Đến lượt bạn 💪
- Chạy cả hai: server một terminal (
node server.js), React terminal kia (npm run dev -- --port 3901). Hai terminal, hai chương trình – chào full-stack! - Thêm
<GuestBook />vào app và thử: viết tin, tải lại trang – tin vẫn còn (miễn server còn chạy). - Điều chỉnh sổ theo dự án: 🏫 tin cho trường · 🙋 bảng tin bạn bè · 🌍 gợi ý “đi đâu?” từ khách · ⚽ khẩu hiệu fan.
- Thử gửi tin trống – frontend cho qua (chưa kiểm tra), server từ chối. Rồi thêm kiểm tra frontend, form lịch sự như Cấp 2.
Tin biến mất khi khởi động lại server – chỉ sống trong mảng bộ nhớ. App thật lưu trong database, sống sót mọi thứ. Đó là việc đầu tiên sau cấp này – từ khóa: SQLite, PostgreSQL.
Tự kiểm tra: Tin từ form đi server, được lưu, và quay lại sau khi tải trang. Bạn vừa xây ứng dụng full-stack – frontend, backend, API. Pro làm vậy mỗi ngày.
Điều cần nhớ từ bài học này
useEffect(..., [])tải dữ liệu lần render đầu;fetchvới POST gửi đi.- Quy tắc sắt bảo mật: server kiểm tra mọi nhập liệu, dù frontend cũng kiểm tra.
- Full-stack = hai chương trình chạy (3901 + 3900) nói qua API.
© 2026 Ing. Martin Polak / AlgoRhino · Điều khoản sử dụng nội dung