React: React Router: موضوعات متقدمة
آخر تحديث: 2026-08-26
نجح توم في تنفيذ التوجيه الأساسي، لكن المتطلبات الجديدة لا تزال تظهر: يجب إعادة توجيه المستخدمين تلقائيًا إلى لوحة التحكم بعد تسجيل الدخول؛ وتتطلب بعض الصفحات تسجيل الدخول للوصول إليها؛ ومع نمو التطبيق، يستغرق تحميل الصفحة الرئيسية وقتًا أطول؛ كما يجب أن تدعم صفحة قائمة المنتجات معلمات التصفية في عنوان URL... وهو بحاجة إلى تعلم الميزات المتقدمة لـ React Router للتعامل مع هذه السيناريوهات الواقعية.
1. ما ستتعلمه
- useNavigate: التنقل البرمجي (إعادة التوجيه بعد تسجيل الدخول، والرجوع إلى الخلف والتقدم إلى الأمام)
- يقوم مكون «Route Guard» بتنفيذ عمليات المصادقة والتفويض
- React.lazy + Suspense للتحميل حسب الطلب
- useSearchParams: إدارة معلمات استعلام عناوين URL
- استراتيجيات لتنظيم واستخراج تكوينات التوجيه
2. المخططات المفاهيمية
flowchart TD
U[User Actions] --> A{Are you logged in??}
A -->|Not logged in| B[ProtectedRoute<br/>→ Redirect to /login]
A -->|Logged in| C{Permissions?}
C -->|No permission| D[→ 403 Page]
C -->|Has permission| E[Load the target page]
E --> F{Is the component lazily loaded??}
F -->|is | G[Suspense<br/>Show loading]
G --> H[Rendering Page]
F -->|No| H
style A fill:#fff3e0,stroke:#f57c00
style B fill:#ffcdd2,stroke:#d32f2f
style G fill:#e1f5fe,stroke:#0288d1
style H fill:#e8f5e9,stroke:#388e3c
طلب المستخدم → يقوم «Route Guard» بالتحقق من تسجيل الدخول/الأذونات → يتم تحميل الصفحة بعد الموافقة (يظهر «جاري التحميل» أثناء التحميل المؤجل) → العرض النهائي.
3. سيناريو واقعي
يتطلب تطبيق توم ما يلي: بعد تسجيل الدخول بنجاح، يجب إعادة توجيه المستخدم تلقائيًا إلى لوحة التحكم؛ ويجب أن تكون صفحة لوحة التحكم محمية بتسجيل الدخول؛ ويجب ألا يُسمح بالوصول إلى لوحة الإدارة إلا للمستخدمين الذين يحملون دور «admin»؛ ويجب أن تُحمَّل الصفحة الرئيسية بسرعة عند الظهور لأول مرة (مع تحميل الصفحات الكبيرة عند الطلب)؛ ويجب أن تتضمن عناوين URL لصفحة قائمة المنتجات معلمات التصفية وتقسيم الصفحات لتسهيل المشاركة.
(1) التنقل البرمجي: useNavigate
يحتاج توم إلى معالجة عمليات إرسال النماذج في صفحة تسجيل الدخول، وعند إتمام الإرسال بنجاح، إعادة توجيه المستخدمين إلى صفحات مختلفة بناءً على أدوارهم. هذا النوع من التنقل، الذي يتم تشغيله بواسطة منطق البرمجة، لا يمكنه استخدام <Link> (نظرًا لأن الروابط لا يمكن تشغيلها إلا بنقرات المستخدمين)؛ وبدلاً من ذلك، يجب استخدام useNavigate.
useNavigate تُرجع دالة navigate تدعم ثلاث طرق للاستدعاء:
| الاستخدام | التأثير | مثال |
|---|---|---|
navigate('/path') |
الانتقال إلى مسار محدد (إضافة إدخال جديد إلى مكدس السجل) | navigate('/dashboard') |
navigate('/path', { replace: true }) |
استبدال السجل الحالي (لا يمكن العودة إلى هذه النقطة) | إعادة التوجيه بعد تسجيل الدخول |
navigate(-1) |
رجوع | العودة إلى الصفحة السابقة |
▶ المثال 1: التنقل البرمجي بعد تسجيل الدخول
import { useNavigate, useLocation } from 'react-router-dom'
function LoginPage() {
const navigate = useNavigate()
const location = useLocation()
// from URL Retrieve the URL to redirect to after login from the query parameters
const from = location.state?.from?.pathname || '/dashboard'
function handleLogin(event) {
event.preventDefault()
const formData = new FormData(event.target)
const username = formData.get('username')
// Simulate a login request
fakeLogin(username).then(user => {
if (user.role === 'admin') {
navigate('/admin', { replace: true }) // Replace Record,Cannot go back to the login page
} else {
navigate(from, { replace: true }) // Redirect to the page you were trying to access before logging in
}
})
}
// Login Form
return (
<form onSubmit={handleLogin}>
<input name="username" placeholder="Username" required />
<button type="submit">Log In</button>
<button type="button" onClick={() => navigate(-1)}>Back</button>
</form>
)
}
// Simulated Login API
async function fakeLogin(username) {
await new Promise(r => setTimeout(r, 500))
return { name: username, role: username === 'admin' ? 'admin' : 'user' }
}
دور useLocation: location.state يمكنه استقبال بيانات الحالة التي يتم تمريرها من Link أو navigate. على سبيل المثال، عند إعادة التوجيه إلى صفحة تسجيل الدخول داخل ProtectedRoute، يمكنك تخزين مسار الصفحة التي كان المستخدم يحاول الوصول إليها في الأصل في state، بحيث يتم إعادة توجيه المستخدم تلقائيًا إلى تلك الصفحة بعد تسجيل الدخول.
(2) حارس المسار: ProtectedRoute
| نوع الحارس | منطق الفحص | السلوك في حالة الفشل | السيناريوهات النموذجية |
|---|---|---|---|
| Login Guard | isAuthenticated |
إعادة التوجيه إلى /login |
لوحة التحكم، حسابي |
| حارس الأذونات | user.role === 'admin' |
إعادة التوجيه إلى /403 |
لوحة الإدارة |
| ميزة «Switch Guard» | featureFlags.xEnabled |
إعادة التوجيه إلى /upgrade |
الميزات المدفوعة |
| الحارس الشرطي | profileComplete |
إعادة التوجيه إلى /onboarding |
دليل تسجيل الدخول لأول مرة |
تتطلب صفحة لوحة التحكم الخاصة بـ«توم» تسجيل الدخول للوصول إليها، كما تتطلب لوحة الإدارة دور «admin». وهو بحاجة إلى آلية «حراسة» — آلية تتحقق من حالة المستخدم قبل عرض الصفحة وتقوم بإعادة توجيهه إذا لم تتوفر الشروط المطلوبة.
في جوهره، يُعد RouteGuard مكونًا مغلفًا: فهو يستقبل المكونات الفرعية وينفذ منطق التحقق من الصحة قبل عرضها. إذا نجح التحقق من الصحة، فإنه يعرض المكونات الفرعية؛ وإلا، فإنه يعيد التوجيه إلى صفحة أخرى باستخدام <Navigate>.
▶ المثال 2: حاجز التوجيه متعدد الطبقات
import { Navigate, useLocation } from 'react-router-dom'
// Simulated Certification Hook
function useAuth() {
return {
user: { name: 'Tom', role: 'admin' }, // In actual projects, starting from Context or store Get
isAuthenticated: true
}
}
// First Floor:Login Guard
function ProtectedRoute({ children }) {
const { isAuthenticated } = useAuth()
const location = useLocation()
if (!isAuthenticated) {
// Save the user's destination to state in ,Redirect back after logging in
return <Navigate to="/login" state={{ from: location }} replace />
}
return children
}
// Second Floor:Character Guard
function AdminRoute({ children }) {
const { user } = useAuth()
if (user.role !== 'admin') {
return <Navigate to="/403" replace />
}
return children
}
// Used in router configuration
function AppRoutes() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/403" element={<AccessDenied />} />
{/* You must log in */}
<Route path="/dashboard" element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
} />
{/* You must log in + admin Character */}
<Route path="/admin" element={
<ProtectedRoute>
<AdminRoute>
<AdminPanel />
</AdminRoute>
</ProtectedRoute>
} />
</Routes>
)
}
نمط الحماية المتداخلة: يقوم ProtectedRoute الخارجي بالتحقق من «ما إذا كان المستخدم قد سجل الدخول»، بينما يتحقق AdminRoute الداخلي من «ما إذا كان المستخدم يتمتع بصلاحيات إدارية». وهذا يؤدي إلى فصل المسؤوليات ويتيح إمكانية إعادة الاستخدام. وإذا دعت الحاجة إلى دور «التحرير» في المستقبل، فما عليك سوى إضافة EditorRoute.
(3) التحميل المؤجل: React.lazy + Suspense
مع نمو التطبيق، لاحظ توم أن تحميل الصفحة الرئيسية أصبح يستغرق وقتًا أطول فأطول — نظرًا لأن جميع أكواد كل الصفحات كانت مجمعة في حزمة واحدة، كان على المستخدمين تنزيل كود لوحة الإدارة كلما زاروا الصفحة الرئيسية. تتيح ميزة React.lazy تقسيم كود المكونات إلى أجزاء منفصلة لا يتم تحميلها إلا عند الحاجة.
import { lazy, Suspense } from 'react'
// These components will not be bundled into the main bundle in
const Dashboard = lazy(() => import('./pages/Dashboard'))
const Settings = lazy(() => import('./pages/Settings'))
const AdminPanel = lazy(() => import('./pages/AdminPanel'))
const UserList = lazy(() => import('./pages/UserList'))
▶ المثال 3: التحميل المؤجل على مستوى المسار
import { lazy, Suspense } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
// Lazy-load all page components
const Home = lazy(() => import('./pages/Home'))
const Dashboard = lazy(() => import('./pages/Dashboard'))
const ProductList = lazy(() => import('./pages/ProductList'))
const ProductDetail = lazy(() => import('./pages/ProductDetail'))
const Settings = lazy(() => import('./pages/Settings'))
const NotFound = lazy(() => import('./pages/NotFound'))
// Loading component
function PageLoader() {
return (
<div style={{
display: 'flex', justifyContent: 'center', alignItems: 'center',
height: '100vh', fontSize: '1.2rem', color: '#666'
}}>
<div className="spinner" />
<span style={{ marginLeft: '12px' }}>Page is loading...</span>
</div>
)
}
function App() {
return (
<BrowserRouter>
{/* Suspense Wrap all lazy-loading routes */}
<Suspense fallback={<PageLoader />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/products" element={<ProductList />} />
<Route path="/products/:id" element={<ProductDetail />} />
<Route path="/settings" element={<Settings />} />
<Route path="*" element={<NotFound />} />
</Routes>
</Suspense>
</BrowserRouter>
)
}
export default App
كيفية عمل التحميل المتأخر: لا يقوم React بتحميل الجزء /dashboard ديناميكيًا إلا عندما يزور المستخدم /dashboard للمرة الأولى. وأثناء التحميل، يتم عرض المكون fallback من Suspense. وبمجرد اكتمال التحميل، يتم استبداله بمكون Dashboard الفعلي.
مزايا الأداء: بافتراض أن الحزمة الأصلية تبلغ 500 كيلوبايت، فإن التحميل المؤجل يقلل حجم الحزمة الرئيسية إلى 100 كيلوبايت، بحيث يبلغ حجم كل صفحة حوالي 80 كيلوبايت. وعندما يزور المستخدمون الصفحة الرئيسية، لا يحتاجون سوى إلى تنزيل 100 كيلوبايت بدلاً من 500 كيلوبايت — مما يؤدي إلى تحسن يبلغ حوالي 5 أضعاف في سرعة التحميل في الجزء المرئي من الصفحة.
4. useSearchParams: إدارة معلمات استعلام عناوين URL
| طريقة معلمات URL | واجهة برمجة التطبيقات (API) | مثال على الصيغة | البيانات القابلة للتطبيق |
|---|---|---|---|
| معلمة المسار | useParams() |
/products/:id → { id: '42' } |
المعرّف المطلوب (معرّف المورد) |
| معلمات الاستعلام | useSearchParams() |
?sort=price&page=2 |
التصفية/الترتيب/التقسيم إلى صفحات (اختياري) |
| هاش | useLocation().hash |
#section-3 |
روابط المرساة للصفحة |
| الحالة | useLocation().state |
navigate('/path', { state }) |
تمرير البيانات المخفية عبر الصفحات |
يجب أن تدعم صفحة قائمة المنتجات الخاصة بـ«توم» ميزات مثل التصفية حسب الفئة، والترتيب حسب السعر، وتقسيم الصفحات، ويجب أن تنعكس معايير التصفية هذه في عنوان URL — حتى يتمكن المستخدمون من مشاركة الروابط التي تم تصفية نتائجها مع الآخرين.
(1) قراءة وكتابة معلمات الاستعلام
useSearchParams تُرجع كائنًا شبيهًا بـ Map يتيح لك قراءة وكتابة معلمات استعلام URL بنفس الطريقة التي تعمل بها Map. وعلى غرار useState، فإنها تُرجع قيمة ووظيفة تعيين.
import { useSearchParams } from 'react-router-dom'
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams()
const category = searchParams.get('category') || 'All'
const sort = searchParams.get('sort') || 'default'
const page = Number(searchParams.get('page')) || 1
function updateFilter(key, value) {
setSearchParams(prev => {
if (value) prev.set(key, value)
else prev.delete(key)
return prev
})
}
return (
<div>
<p>Current Category:{category} | Sort:{sort} | Page: {page}</p>
<button onClick={() => updateFilter('category', 'Electronics')}>Electronics Categories</button>
<button onClick={() => updateFilter('sort', 'price')}>Sort by Price</button>
<button onClick={() => updateFilter('page', String(page + 1))}>Next Page</button>
<button onClick={() => setSearchParams({})}>Clear Filters</button>
</div>
)
}
// URL It will be updated in real time:/products?category=Electronics&sort=price&page=2
▶ المثال 4: وظيفة تصفية المنتجات الكاملة
import { useSearchParams } from 'react-router-dom'
// Simulated Product Data
const allProducts = [
{ id: 1, name: 'iPhone 16', category: 'Electronics', price: 6999 },
{ id: 2, name: 'React Programming Books', category: 'Books', price: 79 },
{ id: 3, name: 'Mechanical Keyboard', category: 'Electronics', price: 399 },
{ id: 4, name: 'Introduction to Design Patterns', category: 'Books', price: 59 },
{ id: 5, name: 'Bluetooth Headphones', category: 'Electronics', price: 899 },
]
function ProductListPage() {
const [searchParams, setSearchParams] = useSearchParams()
// from URL Read Filter Criteria
const category = searchParams.get('category') || ''
const sortBy = searchParams.get('sort') || 'name'
const page = parseInt(searchParams.get('page') || '1', 10)
const pageSize = 3
// Filtering
let filtered = category
? allProducts.filter(p => p.category === category)
: allProducts
// Sort
if (sortBy === 'price') {
filtered = [...filtered].sort((a, b) => a.price - b.price)
} else {
filtered = [...filtered].sort((a, b) => a.name.localeCompare(b.name))
}
// Pagination
const totalPages = Math.ceil(filtered.length / pageSize)
const paged = filtered.slice((page - 1) * pageSize, page * pageSize)
// Update Filter Criteria
function setFilter(key, value) {
setSearchParams(prev => {
const next = new URLSearchParams(prev)
if (value) {
next.set(key, value)
} else {
next.delete(key)
}
next.set('page', '1') // Return to the first page when switching filters
return next
})
}
return (
<div>
<div style={{ marginBottom: '16px' }}>
<label>Categories:
<select value={category} onChange={e => setFilter('category', e.target.value)}>
<option value="">All</option>
<option value="Electronics">Electronics</option>
<option value="Books">Books</option>
</select>
</label>
<label style={{ marginLeft: '16px' }}>Sort:
<select value={sortBy} onChange={e => setFilter('sort', e.target.value)}>
<option value="name">Name</option>
<option value="price">Price</option>
</select>
</label>
</div>
<ul>
{paged.map(p => (
<li key={p.id}>{p.name} — ${p.price}({p.category})</li>
))}
</ul>
<div>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => setSearchParams(prev => {
const next = new URLSearchParams(prev)
next.set('page', String(i + 1))
return next
})}
style={{ fontWeight: page === i + 1 ? 'bold' : 'normal' }}
>
{i + 1}
</button>
))}
</div>
<p>Currently URL:/products?category={category}&sort={sortBy}&page={page}</p>
</div>
)
}
الكلمة المفتاحية: تمثل معلمات الاستعلام في عنوان URL «حالة قابلة للمشاركة». فعندما يقوم المستخدم بتطبيق عوامل التصفية ونسخ عنوان URL لإرساله إلى زميل له، سيشاهد هذا الزميل بالضبط نفس النتائج التي تمت تصفيتها عند فتح الرابط. وهذا الأمر غير ممكن عند استخدام useState لإدارة شروط التصفية.
5. الاستراتيجيات التنظيمية لتكوين مسارات التوجيه
عندما يرتفع عدد مسارات المشروع إلى عدة عشرات، فإن كتابة جميع المسارات في مكون واحد يجعل صيانة الكود أمراً صعباً. لذا، يتعين على توم فصل تكوين المسارات إلى وحدة منفصلة.
(1) ملف تكوين التوجيه
// src/routes/index.js
import { lazy } from 'react'
// Centrally manage all routing definitions
const routes = [
{
path: '/',
component: lazy(() => import('../pages/Home')),
exact: true
},
{
path: '/login',
component: lazy(() => import('../pages/Login')),
},
{
path: '/dashboard',
component: lazy(() => import('../pages/Dashboard')),
protected: true // You must log in
},
{
path: '/admin',
component: lazy(() => import('../pages/AdminPanel')),
protected: true,
adminOnly: true // Required admin Permissions
},
{
path: '/products',
component: lazy(() => import('../pages/ProductList')),
},
{
path: '/products/:id',
component: lazy(() => import('../pages/ProductDetail')),
},
{
path: '*',
component: lazy(() => import('../pages/NotFound')),
}
]
export default routes
▶ المثال 5: مُصوِّر المسار
// src/routes/AppRouter.jsx
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { Suspense } from 'react'
import routes from './index'
import ProtectedRoute from '../components/ProtectedRoute'
import AdminRoute from '../components/AdminRoute'
function renderRoutes(routeList) {
return routeList.map(route => {
const Component = route.component
let element = <Component />
// On-Demand Package Guard
if (route.protected) {
element = <ProtectedRoute>{element}</ProtectedRoute>
}
if (route.adminOnly) {
element = <AdminRoute>{element}</AdminRoute>
}
return (
<Route key={route.path} path={route.path} element={element} />
)
})
}
function AppRouter() {
return (
<BrowserRouter>
<Suspense fallback={<div>Loading......</div>}>
<Routes>
{renderRoutes(routes)}
</Routes>
</Suspense>
</BrowserRouter>
)
}
export default AppRouter
وتتمثل ميزة هذا النهج في أن إعدادات التوجيه تتمركز في مكان واحد، ويتم تغليف منطق الحماية تلقائيًا، ولا تتطلب إضافة صفحة جديدة سوى إضافة كائن إلى routes/index.js.
(2) useLocation: مراقبة تغييرات المسار
بالإضافة إلى التنقل، يحتاج «توم» أيضًا إلى مراقبة التغييرات في المسار في حالات معينة — على سبيل المثال، لإرسال بيانات التتبع عند تغير مسار الصفحة، أو إغلاق النوافذ المنبثقة، أو إعادة تعيين حالات النماذج. يمكن لـ useLocation استرداد معلومات عنوان URL الحالي، وعند استخدامه بالاقتران مع useEffect، يمكنه مراقبة التغييرات في المسار.
import { useLocation } from 'react-router-dom'
import { useEffect } from 'react'
function PageTracker() {
const location = useLocation()
useEffect(() => {
// Triggered whenever the path changes
console.log('Page Views:', location.pathname + location.search)
// Tracking Event Reporting
analytics.pageView({
path: location.pathname,
search: location.search,
timestamp: Date.now()
})
}, [location]) // Dependency location Object
// Note:location.pathname or location.search Any change will trigger
return null // This component does not render anything UI
}
// in App Used in
function App() {
return (
<BrowserRouter>
<PageTracker /> {/* Place Routes External,Always Listen */}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</BrowserRouter>
)
}
الخصائص الرئيسية التي تُرجعها useLocation: pathname (المسار، مثل /products/42)، search (سلسلة الاستعلام، مثل ?category=electronics)، hash (تجزئة عنوان URL، مثل #section-2)، state (بيانات الحالة التي يتم تمريرها عبر Link أو navigate).
❓ أسئلة شائعة
useNavigate وLink؟Link للتنقل الذي يتم تشغيله بنقرات المستخدم (مثل الروابط في شريط التنقل، أو مسار التنقل، أو قوائم المقالات). يُستخدم useNavigate للتنقل الذي يتم تشغيله بواسطة منطق البرمجة (مثل عمليات إعادة التوجيه بعد تسجيل الدخول، أو بعد إرسال النموذج، أو عمليات إعادة التوجيه المجدولة، أو التنقل للخلف/للأمام). القاعدة الأساسية: تفاعل المستخدم → Link؛ منطق البرمجة → useNavigate.ProtectedRoute بالتحقق من «ما إذا كان المستخدم قد سجل الدخول»، بينما يتحقق الحارس الداخلي AdminRoute من «ما إذا كان المستخدم يتمتع بأذونات إدارية». عند تداخل الحراس، تأكد من أن كل حارس يتولى مسؤولية واحدة؛ لا تتحقق من حالة تسجيل الدخول وأذونات الدور معًا ضمن حارس واحد. إذا كان عدد الحراس كبيرًا جدًّا، ففكر في استخدام مصفوفة تكوين مقترنة بحلقة لتغليف طبقات متعددة من الحراس تلقائيًّا.export default)؛ (2) يجب استخدامه داخل مكون Suspense؛ (3) لا يدعم العرض من جانب الخادم (بالنسبة لـ SSR، استخدم @loadable/component بدلاً من ذلك). بالإضافة إلى ذلك، إذا كانت سرعة الشبكة بطيئة أثناء تحميل مكون يتم تحميله بشكل مؤجل، فسيشاهد المستخدمون المحتوى البديل؛ ويوصى بتصميم المحتوى البديل بحيث يكون صغير الحجم وسريعًا.useSearchParams وuseState لإدارة شروط التصفية؟useSearchParams بمزامنة الحالة مع عنوان URL — حيث يمكن للمستخدمين مشاركة الروابط وإضافة الصفحات إلى الإشارات المرجعية والتنقل للأمام وللخلف. أما الحالة التي يديرها useState فتوجد فقط في الذاكرة وتُفقد عند تحديث الصفحة. ومع ذلك، فإن useSearchParams يتسبب في عبء إضافي على الأداء (تؤدي تغييرات عنوان URL إلى إعادة عرض المكون). بالنسبة للسيناريوهات التي تتضمن تحديثات متكررة (مثل سحب شريط التمرير)، يُنصح باستخدام useState أولاً ثم مزامنة الحالة مع عنوان URL بمجرد تأكيدها.📖 ملخص
- تعالج وظيفة useNavigate عمليات التنقل التي يتم تشغيلها بواسطة التعليمات البرمجية (إعادة التوجيه عند تسجيل الدخول، والتنقل إلى الخلف وإلى الأمام)،
replace: trueلمنع تلف مكدس السجل - تم تنفيذ «حارس الموجه» باستخدام مكون غلاف؛ حيث تتولى الطبقة الخارجية التحقق من المصادقة، بينما تتولى الطبقة الداخلية التحقق من الأذونات، مما يضمن التزام كل طبقة بمسؤولية واحدة وإمكانية إعادة الاستخدام.
- تتيح ميزة React.lazy + Suspense تجميع الكود على مستوى المسار، مما يحسّن بشكل كبير سرعة تحميل الشاشة الأولى
- تعمل وظيفة useSearchParams على مزامنة إعدادات التصفية وتقسيم الصفحات مع عنوان URL، مما يدعم مشاركة الروابط والتنقل بين الصفحات السابقة واللاحقة في المتصفح
- إدارة مركزية لإعدادات المسارات + آليات حماية تلقائية لعملية العرض، وهي مثالية لصيانة المشاريع واسعة النطاق
📝 تمارين
- تنفيذ صفحة تسجيل الدخول: بعد أن يقوم المستخدم بإدخال اسم المستخدم الخاص به، استخدم
useNavigateللانتقال إلى لوحة التحكم، واستخدمreplace: trueأثناء عملية الانتقال لمنع المستخدم من العودة إلى صفحة تسجيل الدخول. - استخدم
ProtectedRouteلحماية مسارات لوحة التحكم، بحيث يتم إعادة التوجيه إلى صفحة تسجيل الدخول إذا لم يكن المستخدم مسجلاً للدخول، ثم إعادة التوجيه تلقائيًا إلى الصفحة التي كان المستخدم ينوي زيارتها في الأصل بعد نجاح عملية تسجيل الدخول. - استخدم
useSearchParamsلتنفيذ صفحة قائمة المنتجات: يجب أن تدعم هذه الصفحة التصفية حسب الفئة، والفرز حسب السعر، وتقسيم الصفحات. يجب أن تنعكس معايير التصفية في عنوان URL، كما يجب الحفاظ على معايير التصفية بعد تحديث الصفحة.