العربية

استكشف أنماط التنقل الأساسية مع React Router v6. تعلم التوجيه التعريفي، المسارات الديناميكية، التنقل البرمجي، واستراتيجيات تحميل البيانات لبناء تطبيقات ويب قوية.

React Router v6: إتقان أنماط التنقل لتطبيقات الويب الحديثة

تُعد React Router v6 مكتبة توجيه قوية ومرنة لتطبيقات React. تتيح لك إنشاء تطبيقات الصفحة الواحدة (SPAs) بتجربة مستخدم سلسة من خلال إدارة التنقل دون الحاجة إلى إعادة تحميل الصفحة بالكامل. ستتعمق هذه المقالة في أنماط التنقل الأساسية باستخدام React Router v6، مما يزودك بالمعرفة والأمثلة اللازمة لبناء تطبيقات ويب قوية وسهلة الاستخدام.

فهم المفاهيم الأساسية لـ React Router v6

قبل الغوص في أنماط محددة، دعنا نراجع بعض المفاهيم الأساسية:

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;

في هذا المثال، نحدد ثلاثة مسارات:

يمكّن مكون 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;

في هذا المثال:

مثال التدويل: التعامل مع رموز اللغة

لموقع ويب متعدد اللغات، قد تستخدم مسارًا ديناميكيًا للتعامل مع رموز اللغة:


} />

سيتطابق هذا المسار مع عناوين 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;

في هذا المثال:

تمرير الحالة (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.

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 ( } /> } /> } /> ); }

في هذا المثال:

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 آليات جلب بيانات مدمجة تتكامل بسلاسة مع التوجيه. غالبًا ما توفر هذه المكتبات ميزات مثل:

يمكن أن يؤدي استخدام مثل هذه المكتبة إلى تبسيط تحميل البيانات بشكل كبير وتحسين الأداء، خاصة للتطبيقات المعقدة.

التصيير من جانب الخادم (SSR) وتوليد المواقع الثابتة (SSG)

لتحسين محركات البحث (SEO) وأداء التحميل الأولي، فكر في استخدام SSR أو SSG مع أطر عمل مثل Next.js أو Gatsby. تتيح لك هذه الأطر جلب البيانات على الخادم أو أثناء وقت البناء وتقديم HTML مُصيَّر مسبقًا للعميل. هذا يلغي حاجة العميل لجلب البيانات عند التحميل الأولي، مما يؤدي إلى تجربة أسرع وأكثر ملاءمة لمحركات البحث.

7. العمل مع أنواع مختلفة من الموجهات (Router)

يوفر React Router v6 تطبيقات موجهات مختلفة لتناسب بيئات وحالات استخدام متنوعة:

اختر نوع الموجه الذي يناسب متطلبات وبيئة تطبيقك على أفضل وجه.

الخاتمة

يوفر React Router v6 حلاً شاملاً ومرنًا للتوجيه في تطبيقات React. من خلال فهم وتطبيق أنماط التنقل التي تمت مناقشتها في هذه المقالة، يمكنك بناء تطبيقات ويب قوية وسهلة الاستخدام وقابلة للصيانة. بدءًا من التوجيه التعريفي باستخدام <Routes> و <Route>، إلى المسارات الديناميكية مع معلمات URL، والتنقل البرمجي باستخدام useNavigate، واستراتيجيات تحميل البيانات الفعالة، يمكّنك React Router v6 من إنشاء تجارب تنقل سلسة للمستخدمين. فكر في استكشاف مكتبات التوجيه المتقدمة وأطر عمل SSR/SSG لمزيد من التحكم وتحسين الأداء. تذكر تكييف هذه الأنماط مع متطلبات تطبيقك المحددة وإعطاء الأولوية دائمًا لتجربة مستخدم واضحة وبديهية.