النمط الأساسي: useState + useEffect + fetch
ثلاث حالات نحتاجها دائمًا: البيانات، التحميل، الخطأ.
import { useState, useEffect } from "react";
function Users() {
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("فشل الطلب");
return res.json();
})
.then((data) => setUsers(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, []);
if (loading) return <p>جارٍ التحميل...</p>;
if (error) return <p>خطأ: {error}</p>;
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
بـ async/await (أنظف)
لا يمكن جعل دالة useEffect نفسها async، فنعرّف دالة داخلية:
useEffect(() => {
async function loadUsers() {
try {
const res = await fetch("/api/users");
const data = await res.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
loadUsers();
}, []);
إعادة الجلب عند تغيّر قيمة
useEffect(() => {
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then(setUser);
}, [userId]); // يُعاد الجلب كلما تغيّر userId
تجنّب تحديث مكوّن مُزال (Cleanup)
useEffect(() => {
let active = true;
fetch("/api/data")
.then((res) => res.json())
.then((data) => {
if (active) setData(data); // لا تحدّث إن أُزيل المكوّن
});
return () => { active = false; };
}, []);
ملاحظة: المكتبات الجاهزة
للمشاريع الكبيرة، مكتبات مثل React Query (TanStack Query) تتولّى التحميل والتخزين المؤقّت وإعادة المحاولة تلقائيًا — لكن فهم النمط اليدوي أساس مهم.
الأخطاء الشائعة
- ❌ جعل دالة useEffect نفسها
async→ عرّف دالة داخلية بدلًا منها. - ❌ نسيان حالتي التحميل والخطأ → تجربة سيئة.
- ❌ نسيان مفتاح
keyعند عرض القائمة. - ❌ تحديث الحالة بعد إزالة المكوّن → استخدم علم التنظيف.
خلاصة
اجلب البيانات بنمط useState (data/loading/error) + useEffect + fetch. اعرض حالة التحميل والخطأ، وأعد الجلب عبر الاعتماديات، ونظّف لتجنّب تحديث مكوّن مُزال. هذا أكثر أنماط React استخدامًا.