حمّل بيانات بعيدة باستخدام fetch داخل تأثير، مع نمذجة حالتَي التحميل والخطأ بشكل نظيف.
افتح هذا الدرس في Kodokonيستغرق طلب الشبكة وقتاً ويمكن أن يفشل: يجب أن تعكس واجهتك هذه الحقائق. العُرف المهني هو تتبع ثلاث قطع متمايزة من الحالة: البيانات المستقبَلة، ومنطقي (boolean) للـ التحميل، وخطأ محتمل. يُوضَع الطلب داخل useEffect، لأن الاتصال بخادم هو تأثير جانبي.
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch("https://api.example.com/users")
.then((res) => {
if (!res.ok) throw new Error("HTTP " + res.status);
return res.json();
})
.then((data) => setUsers(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, []);في العرض، عالج الحالات بالترتيب: التحميل أولاً، ثم الخطأ، وأخيراً البيانات. هذه العودة المبكّرة (early returns) تحافظ على قابلية قراءة الشيفرة وتضمن أن يرى المستخدم دائماً شيئاً متسقاً: مؤشر انتظار، أو رسالة فشل، أو القائمة المتوقعة.
if (loading) return <p>Loading…</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);فخّ أخير: إذا تغيّرت تبعية (مثل userId)، يخرج طلب جديد بينما قد يكون القديم لا يزال قيد التنفيذ. إذا أجاب القديم أخيراً، فسيطمس البيانات الحديثة. الإجراء المضاد الكلاسيكي: علَم ignore يُضبط إلى true بواسطة دالة التنظيف، للتخلص من الاستجابات القديمة.
useEffect(() => {
let ignore = false;
setLoading(true);
fetch("/api/users/" + userId)
.then((res) => res.json())
.then((data) => {
if (!ignore) setUser(data);
})
.finally(() => {
if (!ignore) setLoading(false);
});
return () => {
ignore = true;
};
}, [userId]);catch لا يُطلَق أبداً. لماذا؟ignore المضبوط إلى true في تنظيف التأثير؟