← 第 3 关 – 大师

第 9/10 课 ⏱ 60 分钟 高级版

留言板:前端和后端一起

大时刻:把 React 连到服务器。消息终于真的会被保存。

我们要建什么

留言板:React 里的表单把消息发到服务器,服务器保存,给每个后来的访客看。还记得第 2 级没地方发的表单吗?今天还债。

跟我看:留言板后端

my-server 文件夹,先再装一个包:

npm install cors

编辑 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");
});

新东西:

跟我看:留言板前端

在 React 项目创建 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;

React 里最后三样新东西:

轮到你了 💪

  1. 两个都跑起来:一个终端服务器(node server.js),另一个 React(npm run dev -- --port 3901)。两个终端,两个程序——欢迎全栈!
  2. 在应用里加 <GuestBook /> 试试:写留言,刷新页面——留言还在(只要服务器还在跑)。
  3. 按项目改留言板:🏫 给学校的留言 · 🙋 朋友留言板 · 🌍 访客”该去哪?“建议 · ⚽ 球迷口号。
  4. 试发空留言——前端会放行(没检查),服务器拒绝。然后前端也加检查,像第 2 级那样礼貌。
💡

服务器重启留言就消失——它们只存在内存数组里。真正应用存进 数据库,什么都能撑过重启。完成这一级后第一件事就是学——关键词:SQLite、PostgreSQL。

检查一下: 表单的留言到服务器、被保存、刷新后还在。你刚刚建了 全栈应用——前端、后端、API。专业开发者每天就这样做。

这堂课你要记住