React Router — التنقل بين الصفحات في React 2026
دليل عملي مفصل لـ React Router — التنقل، المسارات، الروابط، والمعاملات، مع تمارين وحلول
في المقالات السابقة، بنينا تطبيقات React بصفحة واحدة. لكن التطبيقات الحقيقية تحتاج صفحات متعددة. هنا يأتي دور React Router.
في هذا الدليل العملي، سنأخذك خطوة بخطوة لتعلم React Router وكيفية بناء تطبيق متعدد الصفحات، مع تمارين وحلول.
ما هو React Router؟
React Router هي مكتبة تُضيف التنقل (Routing) لتطبيقات React. تسمح لك بـ:
- تبديل الصفحات بدون إعادة تحميل.
- تمرير معاملات في الرابط.
- حماية المسارات (Auth).
- التنقل المتداخل (Nested Routes).
تشبيه بسيط: تطبيق React الواحد يمكن أن يحتوي على عدة صفحات. React Router هو الموجّه الذي يعرض الصفحة الصحيحة بناءً على الرابط.
لماذا نحتاج React Router؟
بدون React Router:
- ❌ إما صفحة واحدة فقط.
- ❌ أو إعادة تحميل الصفحة لكل تنقل.
مع React Router:
- ✅ صفحات متعددة.
- ✅ تنقل فوري (SPA).
- ✅ روابط قابلة للمشاركة.
- ✅ زر الرجوع يعمل.
أنواع المكتبات
هناك مكتبتان رئيسيتان:
| المكتبة | الوصف | الاستخدام | |---------|-------|-----------| | React Router | المكتبة الكلاسيكية | للـ SPA | | TanStack Router | مكتبة حديثة | Type-safe |
سنستخدم React Router لأنها الأكثر شعبية.
تثبيت React Router
في Terminal، اذهب إلى مشروعك، واكتب:
npm install react-router-dom
النتيجة: ستُضاف المكتبة إلى package.json.
الإعداد الأساسي
1. في src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>
);
شرح: BrowserRouter يُغلّف التطبيق كله ليُتيح التنقل.
2. في src/App.tsx
import { Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import NotFound from "./pages/NotFound";
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
}
export default App;
شرح:
Routes: حاوية لكل المسارات.Route: مسار واحد (path + element).path="*": مسار افتراضي (404).
3. إنشاء الصفحات
أنشئ src/pages/Home.tsx:
function Home() {
return (
<div>
<h1>🏠 الصفحة الرئيسية</h1>
<p>مرحباً بك في موقعنا!</p>
</div>
);
}
export default Home;
أنشئ src/pages/About.tsx:
function About() {
return (
<div>
<h1>ℹ️ من نحن</h1>
<p>نحن فريق عربي متخصص في التقنية.</p>
</div>
);
}
export default About;
أنشئ src/pages/NotFound.tsx:
import { Link } from "react-router-dom";
function NotFound() {
return (
<div style={{ textAlign: "center", padding: 40 }}>
<h1>404</h1>
<p>الصفحة غير موجودة</p>
<Link to="/">العودة للرئيسية</Link>
</div>
);
}
export default NotFound;
التنقل بين الصفحات
1. باستخدام <Link>
import { Link } from "react-router-dom";
function Navbar() {
return (
<nav>
<Link to="/">الرئيسية</Link>
<Link to="/about">من نحن</Link>
<Link to="/contact">اتصل بنا</Link>
</nav>
);
}
الفرق عن <a>:
<a>: يعيد تحميل الصفحة.<Link>: تنقل فوري (SPA).
2. باستخدام useNavigate
import { useNavigate } from "react-router-dom";
function LoginButton() {
const navigate = useNavigate();
const handleClick = () => {
// ... منطق تسجيل الدخول
navigate("/dashboard");
};
return <button onClick={handleClick}>تسجيل الدخول</button>;
}
3. باستخدام NavLink (للروابط النشطة)
import { NavLink } from "react-router-dom";
function Navbar() {
return (
<nav>
<NavLink to="/" className={({ isActive }) => isActive ? "active" : ""}>
الرئيسية
</NavLink>
<NavLink to="/about" className={({ isActive }) => isActive ? "active" : ""}>
من نحن
</NavLink>
</nav>
);
}
الفائدة: NavLink يعرف متى يكون الرابط نشطاً (الصفحة الحالية).
المسارات الديناميكية
1. تعريف المسار
<Route path="/user/:id" element={<UserProfile />} />
:id هو معامل ديناميكي.
2. قراءة المعامل
import { useParams } from "react-router-dom";
function UserProfile() {
const { id } = useParams<{ id: string }>();
return (
<div>
<h1>الملف الشخصي للمستخدم #{id}</h1>
</div>
);
}
النتيجة:
/user/1→ "الملف الشخصي للمستخدم #1"/user/42→ "الملف الشخصي للمستخدم #42"
المسارات المتداخلة (Nested Routes)
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact />} />
</Route>
</Routes>
Layout.tsx:
import { Outlet } from "react-router-dom";
import Navbar from "./Navbar";
function Layout() {
return (
<div>
<Navbar />
<main>
<Outlet /> {/* ← الصفحة الحالية تُعرض هنا */}
</main>
<footer>© 2026</footer>
</div>
);
}
الفائدة: Navbar و Footer يظهران في كل الصفحات.
حماية المسارات (Protected Routes)
import { Navigate } from "react-router-dom";
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const isLoggedIn = localStorage.getItem("token");
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return <>{children}</>;
}
// الاستخدام:
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
مثال عملي: مدونة كاملة
1. الصفحات
src/pages/Home.tsx:
import { Link } from "react-router-dom";
function Home() {
return (
<div>
<h1>📝 مدونتي</h1>
<Link to="/posts">تصفح المقالات</Link>
</div>
);
}
export default Home;
src/pages/Posts.tsx:
import { Link } from "react-router-dom";
const posts = [
{ id: 1, title: "تعلم React", excerpt: "..." },
{ id: 2, title: "تعلم TypeScript", excerpt: "..." },
{ id: 3, title: "بناء API", excerpt: "..." },
];
function Posts() {
return (
<div>
<h1>📚 المقالات</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link to={`/posts/${post.id}`}>{post.title}</Link>
</li>
))}
</ul>
</div>
);
}
export default Posts;
src/pages/PostDetail.tsx:
import { useParams, Link } from "react-router-dom";
const posts = {
"1": { title: "تعلم React", content: "React مكتبة رائعة..." },
"2": { title: "تعلم TypeScript", content: "TypeScript تضيف أنواع..." },
"3": { title: "بناء API", content: "Node.js مع Express..." },
};
function PostDetail() {
const { id } = useParams<{ id: string }>();
const post = posts[id as keyof typeof posts];
if (!post) {
return (
<div>
<p>المقال غير موجود</p>
<Link to="/posts">العودة</Link>
</div>
);
}
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
<Link to="/posts">← العودة للمقالات</Link>
</article>
);
}
export default PostDetail;
2. App.tsx
import { Routes, Route } from "react-router-dom";
import Layout from "./components/Layout";
import Home from "./pages/Home";
import Posts from "./pages/Posts";
import PostDetail from "./pages/PostDetail";
import NotFound from "./pages/NotFound";
function App() {
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="posts" element={<Posts />} />
<Route path="posts/:id" element={<PostDetail />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
);
}
export default App;
الاستعلامات (Query Parameters)
الرابط:
/posts?sort=date&filter=recent
القراءة:
import { useSearchParams } from "react-router-dom";
function Posts() {
const [searchParams, setSearchParams] = useSearchParams();
const sort = searchParams.get("sort");
const filter = searchParams.get("filter");
return (
<div>
<p>الترتيب: {sort}</p>
<p>التصفية: {filter}</p>
<button onClick={() => setSearchParams({ sort: "title" })}>
ترتيب حسب العنوان
</button>
</div>
);
}
تمارين عملية
تمرين 1: موقع بسيط
أنشئ موقعاً بصفحتين: Home و About.
الحل:
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
تمرين 2: Navbar مع Link
أنشئ Navbar بروابط للصفحات.
الحل:
function Navbar() {
return (
<nav>
<Link to="/">الرئيسية</Link>
<Link to="/about">من نحن</Link>
<Link to="/contact">اتصل بنا</Link>
</nav>
);
}
تمرين 3: مسار ديناميكي
أنشئ صفحة /user/:id تعرض رقم المستخدم.
الحل:
function User() {
const { id } = useParams();
return <h1>المستخدم #{id}</h1>;
}
تمرين 4: 404
أنشئ صفحة 404 مع رابط للعودة.
الحل:
function NotFound() {
return (
<div>
<h1>404</h1>
<Link to="/">العودة للرئيسية</Link>
</div>
);
}
تمرين 5: التنقل برمجياً
أنشئ زر ينقلك لصفحة أخرى.
الحل:
function GoButton() {
const navigate = useNavigate();
return <button onClick={() => navigate("/about")}>اذهب لمن نحن</button>;
}
تمرين 6: NavLink نشط
أضف تنسيقاً للرابط النشط.
الحل:
<NavLink to="/about" className={({ isActive }) => isActive ? "active" : ""}>
من نحن
</NavLink>
تمرين 7: مسارات متداخلة
أنشئ Layout مع Navbar و Footer.
الحل:
function Layout() {
return (
<>
<Navbar />
<main><Outlet /></main>
<footer>© 2026</footer>
</>
);
}
تمرين 8: حماية مسار
أنشئ مسار /dashboard محمي.
الحل:
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const isLoggedIn = !!localStorage.getItem("token");
return isLoggedIn ? <>{children}</> : <Navigate to="/login" />;
}
حل المشاكل الشائعة
🔴 المشكلة 1: useNavigate() may be used only in the context of a <Router>
السبب: لم تُغلّف التطبيق بـ BrowserRouter.
الحل: أضف <BrowserRouter> في main.tsx.
🔴 المشكلة 2: الصفحة تُحدّث عند التنقل
السبب: استخدام <a href> بدلاً من <Link>.
الحل: استخدم <Link to="...">.
🔴 المشكلة 3: useParams لا يعمل
السبب: المسار غير ديناميكي.
الحل: تأكد من تعريف :id في المسار.
🔴 المشكلة 4: 404 في الإنتاج
السبب: السيرفر لا يعرف كيف يتعامل مع المسارات.
الحل (Firebase): أضف rewrites في firebase.json:
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
⚠️ مهم جداً: بدون هذا، المسارات المباشرة (مثل /about) لن تعمل في الإنتاج!
جدول مكونات React Router
| المكوّن/الدالة | الوظيفة |
|---|---|
BrowserRouter | يُغلّف التطبيق |
Routes | حاوية المسارات |
Route | مسار واحد |
Link | رابط تنقل |
NavLink | رابط مع حالة نشطة |
Outlet | مكان عرض الصفحات الفرعية |
Navigate | إعادة توجيه |
useNavigate | دالة التنقل |
useParams | قراءة معاملات المسار |
useSearchParams | قراءة query params |
قائمة تحقق نهائية
| المهمة | الحالة |
|---|---|
| تثبيت React Router | ⬜ |
| إعداد BrowserRouter | ⬜ |
| إنشاء Routes و Route | ⬜ |
| استخدام Link و NavLink | ⬜ |
| المسارات الديناميكية | ⬜ |
| المسارات المتداخلة | ⬜ |
| حماية المسارات | ⬜ |
| حل التمارين الثمانية | ⬜ |
⚠️ مهم جداً: إعداد Firebase
لتعمل المسارات في الإنتاج على Firebase، تأكد من أن firebase.json يحتوي على:
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
بدون هذا، ستظهر صفحة 404 عند زيارة أي مسار مباشر.
ماذا بعد هذا المقال؟
الآن بعد أن أتقنت React Router، أنت جاهز للمقال التالي:
- Context API — إدارة الحالة العامة.
- Redux Toolkit — إدارة حالة متقدمة.
- مشروع متكامل — تطبيق كامل.
الخلاصة
في هذا المقال، تعلمت:
- ✅ ما هو React Router ولماذا نحتاجه.
- ✅ تثبيت وإعداد React Router.
- ✅ Routes و Route.
- ✅ Link, NavLink, useNavigate.
- ✅ المسارات الديناميكية (useParams).
- ✅ المسارات المتداخلة (Outlet).
- ✅ حماية المسارات (Protected Routes).
- ✅ حل 8 تمارين عملية.
تذكر: React Router يجعل تطبيقك SPA حقيقي. أتقنه جيداً.
هل أتقنت React Router؟ شاركنا في التعليقات!
القوائم والشروط في React — دليل شامل 2026
Context API في React — إدارة الحالة العامة 2026
📚 مقالات ذات صلة
مشروع React متكامل — تطبيق متجر إلكتروني 2026
مشروع عملي شامل لبناء تطبيق متجر إلكتروني بـ React و TypeScript — مع السلة، البحث، التصفية، والحفظ التلقائي
Context API في React — إدارة الحالة العامة 2026
دليل عملي مفصل لـ Context API في React — إنشاء Context، Provider، useContext، مع تمارين وحلول
القوائم والشروط في React — دليل شامل 2026
دليل عملي مفصل للقوائم والشروط في React — map, filter, key، والتصيير الشرطي، مع تمارين وحلول