دليل تعلّم React Router: إنشاء المسارات والتنقل الاحترافي في تطبيقات React

دقائق القراءة: 8

ما هو React Router ولماذا يُعد أساسياً في تطبيقات React؟

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

في هذا الدليل العملي، ستتعرّف على أهم المفاهيم الأساسية في React Router، بدءاً من إعداد المشروع وتثبيت المكتبة، وصولاً إلى المسارات المتداخلة، وقراءة المعاملات من الرابط، وإعادة التوجيه، وإنشاء صفحات محمية، بالإضافة إلى التعامل مع صفحات الخطأ من نوع 404.

شرح مكتبة React Router للتنقل بين الصفحات داخل تطبيقات React

الموضوعات التي يغطيها هذا الدليل

  • تهيئة مشروع React جديد.
  • إنشاء مكوّن رأس الصفحة Header.
  • تثبيت مكتبة react-router-dom.
  • استخدام BrowserRouter.
  • إنشاء المسارات الأساسية.
  • اختبار المسارات والتحكم في المطابقة.
  • استخدام الخاصية exact.
  • تنظيم المسارات عبر Switch.
  • التنقل باستخدام Link.
  • الاستفادة من basename وforceRefresh.
  • التعامل مع 404 Not Found.
  • قراءة URL Params عبر useParams.
  • قراءة Query String عبر useLocation.
  • إعادة التوجيه باستخدام Redirect.
  • التحكم بالتنقل برمجياً عبر useHistory.
  • إنشاء Nested Routes.

تهيئة مشروع React جديد

للبداية، يمكن إنشاء مشروع جديد باستخدام أداة create-react-app. هذه الخطوة تجهّز لك هيكل المشروع الأساسي وتثبّت الاعتماديات اللازمة تلقائياً.

npx create-react-app react-router-tutorial

بعد إنشاء المشروع، انتقل إلى المجلد وشغّل بيئة التطوير:

cd react-router-tutorial
npm start

عند تشغيل المشروع، يمكنك تنظيف الملفات الافتراضية غير الضرورية داخل مجلد src لتبدأ ببنية أبسط وأكثر وضوحاً.

إنشاء مكوّن Header وتنظيم واجهة التطبيق

من الجيد إنشاء مجلد باسم components لتخزين المكونات القابلة لإعادة الاستخدام. على سبيل المثال، يمكنك إنشاء ملف Header.js ووضع عنوان أو قائمة تنقل بداخله. هذا التنظيم ليس إلزامياً، لكنه يُعد من أفضل الممارسات في المشاريع المتوسطة والكبيرة.

كما يمكنك إنشاء مجلد آخر باسم pages لتخزين الصفحات الرئيسية مثل:

  • Home.js
  • About.js
  • Profile.js

تثبيت مكتبة react-router-dom

حتى تتمكن من استخدام المسارات داخل التطبيق، ثبّت مكتبة react-router-dom بالأمر التالي:

npm i react-router-dom

بعد اكتمال التثبيت، ستكون المكتبة جاهزة للاستخدام داخل مكونات التطبيق.

استخدام BrowserRouter لتفعيل نظام التوجيه

الخطوة الأولى بعد التثبيت هي تغليف التطبيق بالكامل بالمكوّن BrowserRouter. هذا المكوّن هو المسؤول عن تتبع عنوان الصفحة الحالي وربطه بالمكوّن المناسب داخل التطبيق.

import { BrowserRouter } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <div>
        <h1>React Router Tutorial</h1>
      </div>
    </BrowserRouter>
  );
}

بدون BrowserRouter لن تتمكن بقية أدوات التوجيه من العمل بشكل صحيح.

إنشاء المسارات الأساسية في React Router

بعد تفعيل نظام التوجيه، يمكنك إنشاء مسارات متعددة لصفحات مختلفة مثل الصفحة الرئيسية وصفحة من نحن والملف الشخصي.

import { BrowserRouter, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Profile from './pages/Profile';

function App() {
  return (
    <BrowserRouter>
      <Route path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route path="/profile" component={Profile} />
    </BrowserRouter>
  );
}

كل مكوّن Route يربط مساراً معيناً بمكوّن محدد. عند زيارة المسار المناسب، يتم عرض المكوّن المرتبط به.

مشكلة المطابقة الجزئية وحلّها باستخدام exact

عند تعريف المسار / للصفحة الرئيسية، قد تلاحظ أنه يظهر أيضاً مع مسارات أخرى مثل /about أو /profile. يحدث ذلك لأن المطابقة تكون جزئية بشكل افتراضي.

لحل هذه المشكلة، استخدم الخاصية exact حتى تتم مطابقة المسار بشكل كامل فقط:

<Route exact path="/" component={Home} />

بهذه الطريقة، لن يتم عرض الصفحة الرئيسية إلا عند زيارة المسار / فقط.

تنظيم المسارات باستخدام Switch

يوفر Switch أسلوباً أكثر دقة في التعامل مع المسارات، إذ يقوم بعرض أول مسار مطابق فقط. هذا يساعد على تجنّب التعارضات ويجعل ترتيب المسارات مهماً داخل التطبيق.

import { Switch, Route } from 'react-router-dom';

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/profile" component={Profile} />
</Switch>

يفيد Switch أيضاً عند تعريف صفحة الخطأ 404 في نهاية قائمة المسارات.

إنشاء قائمة تنقل احترافية باستخدام Link

في تطوير الويب التقليدي، يُستخدم الوسم <a> للانتقال بين الصفحات. لكن داخل تطبيقات React، يسبّب هذا الوسم إعادة تحميل الصفحة بالكامل، وهو ما يُفقد التطبيق ميزة التنقل السريع.

لذلك، يُفضّل استخدام المكوّن Link المدمج في react-router-dom:

import { Link } from 'react-router-dom';

function Header() {
  return (
    <ul className="nav">
      <li><Link to="/">Home</Link></li>
      <li><Link to="/about">About</Link></li>
      <li><Link to="/profile">Profile</Link></li>
    </ul>
  );
}

ميزة Link أنه يبدّل الصفحة من دون تحديث كامل للمتصفح، ما يحسّن الأداء وتجربة المستخدم.

خصائص مهمة في BrowserRouter

استخدام basename

إذا كان التطبيق يعمل داخل مسار فرعي مثل /tutorial، يمكنك تعريف ذلك عبر الخاصية basename:

<BrowserRouter basename="/tutorial">
  {/* routes */}
</BrowserRouter>

هذا مفيد عند نشر التطبيق داخل مجلد فرعي وليس على الجذر الرئيسي للموقع.

استخدام forceRefresh

في بعض الحالات الخاصة، قد تحتاج إلى إجبار التطبيق على إعادة تحميل الصفحة عند التنقل بين المسارات. يمكن فعل ذلك عبر الخاصية forceRefresh:

<BrowserRouter forceRefresh={true}>
  {/* routes */}
</BrowserRouter>

مع ذلك، نادراً ما يُنصح باستخدامها، لأن فلسفة التطبيقات الأحادية الصفحة SPA تعتمد على تقليل إعادة التحميل.

استخدام getUserConfirmation

تُستخدم الخاصية getUserConfirmation عندما تحتاج إلى طلب تأكيد من المستخدم قبل الانتقال إلى مسار آخر، مثل وجود بيانات غير محفوظة داخل نموذج.

<BrowserRouter
  getUserConfirmation={(message, callback) => {
    callback(window.confirm(message));
  }}
>
  {/* routes */}
</BrowserRouter>

هذه الخاصية مفيدة في السيناريوهات التي تتطلب حماية من فقدان البيانات.

التمرير إلى أعلى الصفحة عند تغيير المسار

في بعض الصفحات الطويلة، قد ينتقل المستخدم إلى مسار جديد بينما يبقى التمرير في نفس الموضع السابق، مما يسبب تجربة استخدام غير مريحة. يمكن معالجة ذلك باستخدام useEffect مع الدالة window.scrollTo().

import { useEffect } from 'react';

function Home() {
  useEffect(() => {
    window.scrollTo(0, 0);
  }, []);

  return <h1>Home Page</h1>;
}

يفضّل تطبيق هذا السلوك في الصفحات الطويلة أو عبر مكوّن مشترك لإدارة الانتقال بين المسارات.

إنشاء صفحة 404 Not Found

من الضروري عرض رسالة واضحة عند دخول المستخدم إلى مسار غير موجود. لهذا الغرض، أنشئ صفحة مخصصة مثل NotFound.js ثم ضع مسارها في نهاية Switch.

import NotFound from './pages/NotFound';

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/profile" component={Profile} />
  <Route component={NotFound} />
</Switch>

أي مسار لا يطابق التعريفات السابقة سيؤدي إلى عرض صفحة 404 تلقائياً.

قراءة المعاملات من الرابط عبر URL Params

من أكثر الاستخدامات شيوعاً في React Router إنشاء صفحات ديناميكية، مثل عرض منشور أو منتج بناءً على رقم المعرّف داخل الرابط.

<Route path="/post/:id" component={Post} />

في المثال السابق، تم تعريف :id كمعامل ديناميكي يمكن قراءته داخل المكوّن المرتبط.

الوصول إلى المعامل عبر match.params

function Post({ match }) {
  return <h2>ID is {match.params.id}</h2>;
}

الوصول إلى المعامل عبر useParams

الطريقة الأحدث والأكثر وضوحاً هي استخدام الخطاف useParams:

import { useParams } from 'react-router-dom';

function Post() {
  const { id } = useParams();

  return <h2>ID is {id}</h2>;
}

يُعد useParams خياراً ممتازاً عندما تريد كتابة مكونات أكثر نظافة وسهولة في القراءة.

قراءة Query String باستخدام useLocation

أحياناً لا تحتاج إلى تغيير بنية المسار نفسه، بل تريد فقط تمرير متغيرات إضافية في الرابط مثل الاسم أو الفئة أو ترتيب النتائج. هنا يأتي دور Query String مع الخطاف useLocation.

مثال على رابط يحتوي على متغيرات:

/post/123?first=Piyush&last=Agarwal

لقراءة هذه القيم داخل المكوّن:

import { useLocation } from 'react-router-dom';

function Post() {
  const { search } = useLocation();
  const query = new URLSearchParams(search);

  return (
    <>
      <h2>First: {query.get('first')}</h2>
      <h2>Last: {query.get('last')}</h2>
    </>
  );
}

هذه الطريقة مفيدة جداً في صفحات البحث، والتصفية، والفرز، وصفحات المحتوى الديناميكي.

إعادة التوجيه وإنشاء المسارات المحمية

في التطبيقات الحقيقية، لا تكون كل الصفحات متاحة لجميع المستخدمين. على سبيل المثال، قد ترغب في السماح بالوصول إلى صفحة الملف الشخصي فقط بعد تسجيل الدخول.

الحماية باستخدام Redirect

import { Redirect, Route } from 'react-router-dom';

<Route path="/profile">
  {login ? <Profile /> : <Redirect to="/" />}
</Route>

إذا كانت قيمة login تساوي false، فسيتم توجيه المستخدم مباشرة إلى الصفحة الرئيسية.

الحماية باستخدام useHistory

يمكن أيضاً تنفيذ إعادة التوجيه برمجياً داخل المكوّن نفسه باستخدام useHistory مع useEffect.

import { useEffect } from 'react';
import { useHistory } from 'react-router-dom';

function Profile({ login }) {
  const history = useHistory();

  useEffect(() => {
    if (!login) {
      history.push('/');
    }
  }, [login, history]);

  return <h1>Profile Page</h1>;
}

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

إنشاء مسارات متداخلة Nested Routing

المسارات المتداخلة مفيدة عندما تحتاج إلى صفحات فرعية داخل صفحة رئيسية، مثل صفحة الملف الشخصي التي تحتوي على:

  • عرض الملف الشخصي
  • تعديل الملف الشخصي

هنا يمكن استخدام useRouteMatch للحصول على path وurl الحاليين وبناء المسارات الفرعية اعتماداً عليهما.

import { Link, Route, Switch, useRouteMatch } from 'react-router-dom';
import ViewProfile from '../components/ViewProfile';
import EditProfile from '../components/EditProfile';

function Profile() {
  const { path, url } = useRouteMatch();

  return (
    <>
      <Link to={`${url}/view-profile`}>View Profile</Link>
      <Link to={`${url}/edit-profile`}>Edit Profile</Link>

      <Switch>
        <Route path={`${path}/view-profile`} component={ViewProfile} />
        <Route path={`${path}/edit-profile`} component={EditProfile} />
      </Switch>
    </>
  );
}

بهذا الأسلوب، ستظل المسارات الفرعية مرتبطة منطقياً بصفحة Profile دون التأثير على بقية بنية التطبيق.

أفضل ممارسات عند استخدام React Router

  • استخدم Link بدلاً من الوسم <a> للتنقل الداخلي.
  • ضع صفحة 404 في نهاية Switch.
  • اعتمد على useParams وuseLocation لتبسيط قراءة البيانات من الرابط.
  • نظّم المشروع بفصل الصفحات داخل مجلد pages والمكونات المشتركة داخل components.
  • طبّق المسارات المحمية على الصفحات الحساسة مثل الحسابات ولوحات التحكم.
  • استخدم المسارات المتداخلة عندما تكون هناك صفحات فرعية مرتبطة بسياق صفحة رئيسية.

متى تحتاج إلى React Router فعلاً؟

إذا كان تطبيقك يتكوّن من واجهة واحدة بسيطة، فقد لا تحتاج إلى نظام توجيه متكامل. لكن بمجرد أن يبدأ التطبيق في التوسع ويحتوي على صفحات مثل:

  • الصفحة الرئيسية
  • صفحة تعريفية
  • ملف شخصي
  • صفحات منتجات أو مقالات
  • لوحة تحكم

فإن React Router يصبح أداة أساسية لتنظيم التنقل وإدارة عرض المكونات بناءً على الرابط الحالي.

الخلاصة التقنية

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

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *