استكشف أنماط التنقل الأساسية مع React Router v6. تعلم التوجيه التعريفي، المسارات الديناميكية، التنقل البرمجي، واستراتيجيات تحميل البيانات لبناء تطبيقات ويب قوية.
React Router v6: إتقان أنماط التنقل لتطبيقات الويب الحديثة
تُعد React Router v6 مكتبة توجيه قوية ومرنة لتطبيقات React. تتيح لك إنشاء تطبيقات الصفحة الواحدة (SPAs) بتجربة مستخدم سلسة من خلال إدارة التنقل دون الحاجة إلى إعادة تحميل الصفحة بالكامل. ستتعمق هذه المقالة في أنماط التنقل الأساسية باستخدام React Router v6، مما يزودك بالمعرفة والأمثلة اللازمة لبناء تطبيقات ويب قوية وسهلة الاستخدام.
فهم المفاهيم الأساسية لـ React Router v6
قبل الغوص في أنماط محددة، دعنا نراجع بعض المفاهيم الأساسية:
- التوجيه التعريفي (Declarative Routing): يستخدم React Router نهجًا تعريفيًا، حيث تحدد مساراتك كمكونات React. هذا يجعل منطق التوجيه الخاص بك واضحًا وسهل الصيانة.
- المكونات: تشمل المكونات الأساسية
BrowserRouter
، وHashRouter
، وMemoryRouter
، وRoutes
، وRoute
. - الخطافات (Hooks): يوفر React Router خطافات مثل
useNavigate
، وuseLocation
، وuseParams
، وuseRoutes
للوصول إلى معلومات التوجيه والتحكم في التنقل.
1. التوجيه التعريفي باستخدام <Routes>
و <Route>
يكمن أساس React Router v6 في التوجيه التعريفي. يمكنك تحديد مساراتك باستخدام مكوني <Routes>
و <Route>
. يعمل مكون <Routes>
كحاوية لمساراتك، ويحدد مكون <Route>
مسارًا معينًا والمكون الذي سيتم عرضه عندما يتطابق هذا المسار مع عنوان URL الحالي.
مثال: إعداد المسارات الأساسية
إليك مثال أساسي لإعداد المسارات لتطبيق بسيط:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";
function App() {
return (
} />
} />
} />
);
}
export default App;
في هذا المثال، نحدد ثلاثة مسارات:
/
: يعرض مكونHome
./about
: يعرض مكونAbout
./contact
: يعرض مكونContact
.
يمكّن مكون BrowserRouter
التوجيه المعتمد على سجل المتصفح. يقوم React Router بمطابقة عنوان URL الحالي مع المسارات المحددة ويعرض المكون المقابل.
2. المسارات الديناميكية مع معلمات URL
تتيح لك المسارات الديناميكية إنشاء مسارات يمكنها التعامل مع قيم مختلفة في عنوان URL. هذا مفيد لعرض المحتوى بناءً على معرف فريد، مثل معرف المنتج أو معرف المستخدم. يستخدم React Router v6 الرمز :
لتحديد معلمات URL.
مثال: عرض تفاصيل المنتج
لنفترض أن لديك تطبيقًا للتجارة الإلكترونية وتريد عرض تفاصيل كل منتج بناءً على معرفه. يمكنك تحديد مسار ديناميكي مثل هذا:
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom";
function ProductDetails() {
const { productId } = useParams();
// جلب تفاصيل المنتج بناءً على productId
// ...
return (
Product Details
Product ID: {productId}
{/* عرض تفاصيل المنتج هنا */}
);
}
function App() {
return (
} />
);
}
export default App;
في هذا المثال:
/products/:productId
يحدد مسارًا ديناميكيًا حيث:productId
هو معلمة URL.- يُستخدم خطاف
useParams
للوصول إلى قيمة المعلمةproductId
داخل مكونProductDetails
. - يمكنك بعد ذلك استخدام
productId
لجلب تفاصيل المنتج المقابلة من مصدر بياناتك.
مثال التدويل: التعامل مع رموز اللغة
لموقع ويب متعدد اللغات، قد تستخدم مسارًا ديناميكيًا للتعامل مع رموز اللغة:
} />
سيتطابق هذا المسار مع عناوين URL مثل /en/about
، و/fr/about
، و/es/about
. يمكن بعد ذلك استخدام المعلمة lang
لتحميل موارد اللغة المناسبة.
3. التنقل البرمجي باستخدام useNavigate
بينما يعد التوجيه التعريفي رائعًا للروابط الثابتة، إلا أنك تحتاج غالبًا إلى التنقل برمجيًا بناءً على إجراءات المستخدم أو منطق التطبيق. يوفر React Router v6 خطاف useNavigate
لهذا الغرض. يُرجع useNavigate
دالة تتيح لك التنقل إلى مسارات مختلفة.
مثال: إعادة التوجيه بعد إرسال النموذج
لنفترض أن لديك نموذجًا يتم إرساله وتريد إعادة توجيه المستخدم إلى صفحة نجاح بعد إرسال النموذج بنجاح:
import { useNavigate } from "react-router-dom";
function MyForm() {
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
// إرسال بيانات النموذج
// ...
// إعادة التوجيه إلى صفحة النجاح بعد الإرسال الناجح
navigate("/success");
};
return (
);
}
export default MyForm;
في هذا المثال:
- نستخدم خطاف
useNavigate
للحصول على دالةnavigate
. - بعد إرسال النموذج بنجاح، نستدعي
navigate("/success")
لإعادة توجيه المستخدم إلى مسار/success
.
تمرير الحالة (State) أثناء التنقل
يمكنك أيضًا تمرير الحالة مع التنقل باستخدام الوسيط الثاني لدالة navigate
:
navigate("/confirmation", { state: { orderId: "12345" } });
يتيح لك هذا تمرير البيانات إلى المكون الهدف، والتي يمكن الوصول إليها باستخدام خطاف useLocation
.
4. المسارات المتداخلة والتخطيطات
تتيح لك المسارات المتداخلة إنشاء هياكل توجيه هرمية، حيث يكون مسار ما متداخلًا داخل مسار آخر. هذا مفيد لتنظيم التطبيقات المعقدة ذات المستويات المتعددة من التنقل. يساعد هذا في إنشاء تخطيطات تكون فيها بعض عناصر واجهة المستخدم موجودة باستمرار عبر قسم من التطبيق.
مثال: قسم ملف تعريف المستخدم
لنفترض أن لديك قسمًا لملف تعريف المستخدم به مسارات متداخلة لعرض معلومات ملف المستخدم وإعداداته وطلباته:
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function Profile() {
return (
User Profile
-
Profile Information
-
Settings
-
Orders
} />
} />
} />
);
}
function ProfileInformation() {
return Profile Information Component
;
}
function Settings() {
return Settings Component
;
}
function Orders() {
return Orders Component
;
}
function App() {
return (
} />
);
}
export default App;
في هذا المثال:
- المسار
/profile/*
يطابق أي عنوان URL يبدأ بـ/profile
. - يعرض مكون
Profile
قائمة تنقل ومكون<Routes>
للتعامل مع المسارات المتداخلة. - تحدد المسارات المتداخلة المكونات التي سيتم عرضها لـ
/profile/info
و/profile/settings
و/profile/orders
.
الرمز *
في المسار الأصلي حاسم؛ إنه يشير إلى أن المسار الأصلي يجب أن يطابق أي مسار فرعي، مما يسمح بمطابقة المسارات المتداخلة بشكل صحيح داخل مكون Profile
.
5. التعامل مع أخطاء "لم يتم العثور عليه" (404)
من الضروري التعامل مع الحالات التي يتنقل فيها المستخدم إلى مسار غير موجود. يسهل React Router v6 هذا الأمر من خلال مسار شامل (catch-all route).
مثال: تنفيذ صفحة 404
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function NotFound() {
return (
404 - Not Found
The page you are looking for does not exist.
Go back to home
);
}
function App() {
return (
} />
} />
} />
);
}
في هذا المثال:
- المسار
<Route path="*" element={<NotFound />} />
هو مسار شامل يطابق أي عنوان URL لا يتطابق مع أي من المسارات المحددة الأخرى. - من المهم وضع هذا المسار في نهاية مكون
<Routes>
بحيث لا يتطابق إلا إذا لم يتطابق أي مسار آخر.
6. استراتيجيات تحميل البيانات مع React Router v6
لا يتضمن React Router v6 آليات تحميل بيانات مدمجة مثل سابقه (React Router v5 مع `useRouteMatch`). ومع ذلك، فإنه يوفر الأدوات اللازمة لتنفيذ استراتيجيات تحميل البيانات المختلفة بفعالية.
الخيار 1: جلب البيانات في المكونات
أبسط طريقة هي جلب البيانات مباشرة داخل المكون الذي يعرض المسار. يمكنك استخدام خطاف useEffect
لجلب البيانات عند تحميل المكون أو عند تغيير معلمات URL.
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
function ProductDetails() {
const { productId } = useParams();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchProduct() {
try {
const response = await fetch(`/api/products/${productId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setProduct(data);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchProduct();
}, [productId]);
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
if (!product) return Product not found
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
هذه الطريقة مباشرة ولكنها يمكن أن تؤدي إلى تكرار الكود إذا كنت بحاجة إلى جلب البيانات في مكونات متعددة. كما أنها أقل كفاءة لأن جلب البيانات لا يبدأ إلا بعد تحميل المكون.
الخيار 2: استخدام خطاف مخصص لجلب البيانات
لتقليل تكرار الكود، يمكنك إنشاء خطاف مخصص يغلف منطق جلب البيانات. يمكن بعد ذلك إعادة استخدام هذا الخطاف في مكونات متعددة.
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
بعد ذلك، يمكنك استخدام هذا الخطاف في مكوناتك:
import { useParams } from "react-router-dom";
import useFetch from "./useFetch";
function ProductDetails() {
const { productId } = useParams();
const { data: product, loading, error } = useFetch(`/api/products/${productId}`);
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
if (!product) return Product not found
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
الخيار 3: استخدام مكتبة توجيه مع إمكانيات جلب البيانات (TanStack Router, Remix)
تقدم مكتبات مثل TanStack Router و Remix آليات جلب بيانات مدمجة تتكامل بسلاسة مع التوجيه. غالبًا ما توفر هذه المكتبات ميزات مثل:
- المحملات (Loaders): وظائف يتم تنفيذها *قبل* عرض المسار، مما يتيح لك جلب البيانات وتمريرها إلى المكون.
- الإجراءات (Actions): وظائف تتعامل مع عمليات إرسال النماذج وتعديلات البيانات.
يمكن أن يؤدي استخدام مثل هذه المكتبة إلى تبسيط تحميل البيانات بشكل كبير وتحسين الأداء، خاصة للتطبيقات المعقدة.
التصيير من جانب الخادم (SSR) وتوليد المواقع الثابتة (SSG)
لتحسين محركات البحث (SEO) وأداء التحميل الأولي، فكر في استخدام SSR أو SSG مع أطر عمل مثل Next.js أو Gatsby. تتيح لك هذه الأطر جلب البيانات على الخادم أو أثناء وقت البناء وتقديم HTML مُصيَّر مسبقًا للعميل. هذا يلغي حاجة العميل لجلب البيانات عند التحميل الأولي، مما يؤدي إلى تجربة أسرع وأكثر ملاءمة لمحركات البحث.
7. العمل مع أنواع مختلفة من الموجهات (Router)
يوفر React Router v6 تطبيقات موجهات مختلفة لتناسب بيئات وحالات استخدام متنوعة:
- BrowserRouter: يستخدم واجهة برمجة تطبيقات سجل HTML5 (
pushState
,replaceState
) للتنقل. وهو الخيار الأكثر شيوعًا لتطبيقات الويب التي تعمل في بيئة المتصفح. - HashRouter: يستخدم جزء الهاش (
#
) من عنوان URL للتنقل. هذا مفيد للتطبيقات التي تحتاج إلى دعم المتصفحات القديمة أو التي يتم نشرها على خوادم لا تدعم واجهة برمجة تطبيقات سجل HTML5. - MemoryRouter: يحتفظ بسجل "عنوان URL" الخاص بك في الذاكرة (مصفوفة من عناوين URL). مفيد في بيئات مثل React Native والاختبار.
اختر نوع الموجه الذي يناسب متطلبات وبيئة تطبيقك على أفضل وجه.
الخاتمة
يوفر React Router v6 حلاً شاملاً ومرنًا للتوجيه في تطبيقات React. من خلال فهم وتطبيق أنماط التنقل التي تمت مناقشتها في هذه المقالة، يمكنك بناء تطبيقات ويب قوية وسهلة الاستخدام وقابلة للصيانة. بدءًا من التوجيه التعريفي باستخدام <Routes>
و <Route>
، إلى المسارات الديناميكية مع معلمات URL، والتنقل البرمجي باستخدام useNavigate
، واستراتيجيات تحميل البيانات الفعالة، يمكّنك React Router v6 من إنشاء تجارب تنقل سلسة للمستخدمين. فكر في استكشاف مكتبات التوجيه المتقدمة وأطر عمل SSR/SSG لمزيد من التحكم وتحسين الأداء. تذكر تكييف هذه الأنماط مع متطلبات تطبيقك المحددة وإعطاء الأولوية دائمًا لتجربة مستخدم واضحة وبديهية.