ماذا نبني
سجل زوار: نموذج في React يرسل رسالة إلى خادمك، والخادم يحفظها، ويعرضها لكل زائر لاحق. تتذكّر نموذج المستوى 2 الذي لم يكن له مكان يرسل إليه شيئاً؟ اليوم نسدّ ذلك الدين.
شاهد معي: backend سجل الزوار
في مجلد 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");
});
ما هو جديد:
cors()– الـ frontend يعمل على المنفذ 3901، والخادم على 3900. المتصفحات عادة تمنع طلبات «عبر الأصول» كهذه (قاعدة أمان تسمى CORS)؛ هكذا تسمح بها على الخادم.app.post(...)– أول endpoint من نوع POST لك! بيانات النموذج تظهر فيrequest.body.- الفحص على الخادم – الـ frontend يفحص النموذج أصلاً، لكن المهاجم يمكنه تجاوز النموذج وإرسال طلب مباشرة. لذلك القاعدة الحديدية: الـ backend يفحص دائماً، ولا يثق أبداً بالـ frontend.
status(400)تعني «طلب سيئ.»
شاهد معي: frontend سجل الزوار
في مشروع 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:
useEffect(() => {...}, [])– «نفّذ هذا مرة، عندما يظهر الـ component أول مرة.» المكان المثالي لتحميل البيانات.fetchمعmethod: "POST"– نرسل بيانات؛JSON.stringifyيعبّئها في JSON.- نماذج متصلة – الحقل يقرأ قيمته من الـ state (
value={name}) ويكتبها أثناء الكتابة (onChange). النموذج والـ state يبقيان متزامنين دائماً.
دورك الآن 💪
- شغّل الاثنين: الخادم في طرفية (
node server.js)، وReact في الأخرى (npm run dev -- --port 3901). طرفيتان، برنامجان – مرحباً بـ full-stack! - أضف
<GuestBook />إلى تطبيقك وجرّبه: اكتب رسالة، أعد تحميل الصفحة – الرسالة لا تزال هناك (طالما الخادم يعمل). - كيّف سجل الزوار لمشروعك: 🏫 رسائل للمدرسة · 🙋 لوحة رسائل للأصدقاء · 🌍 نصائح الزوار «إلى أين نذهب؟» · ⚽ هتافات المشجعين.
- جرّب إرسال رسالة فارغة – الـ frontend يسمح بها (لا فحص فيه)، لكن الخادم يرفضها. ثم أضف فحصاً إلى الـ frontend أيضاً، ليكون النموذج مهذباً كما كان في المستوى 2.
الرسائل تختفي عند إعادة تشغيل الخادم – تعيش فقط في array في الذاكرة. التطبيقات الحقيقية تحفظها في قاعدة بيانات، تبقى بعد أي شيء. هذا أول ما تتعلّمه بعد إنهاء هذا المستوى – الكلمات المفتاحية: SQLite، PostgreSQL.
تحقق من نفسك: رسالة من النموذج تسافر إلى الخادم، تُحفظ، وتعور بعد إعادة تحميل الصفحة. لقد بنيت للتو تطبيقاً full-stack – frontend، backend، API. هذا بالضبط ما يفعله المطوّرون المحترفون كل يوم.
ما ستخرج به من هذا الدرس
useEffect(..., [])يحمّل البيانات عند أول رسم؛ وfetchمع POST يرسلها.- قاعدة الأمان الحديدية: الخادم يفحص كل إدخال، حتى عندما يفحص الـ frontend أيضاً.
- Full-stack = برنامجان يعملان (3901 + 3900) يتحدثان عبر API.
© 2026 Ing. Martin Polak / AlgoRhino · شروط استخدام المحتوى