حماية المسارات والتوجيه البرمجي (Protected Routes & useNavigate)
| التقنية البرمجية | useNavigate Hook | Navigate Component (Protected Route) |
|---|---|---|
| الآلية والوظيفة | توجيه المستخدم برمجياً عبر الكود عند حدوث حدث معين (Imperative Navigation) | إعادة تحويل المستخدم استجابياً فور محاولة فتح مسار غير مسموح له (Declarative Redirect) |
| الاستخدام النموذجي | بعد إتمام الإرسال في النماذج (مثل التسجيل أو الدفع) لتوجيهه للرئيسية | تغليف مسارات لوحة التحكم وصفحات البروفايل لمنع فتحها بدون تسجيل دخول |
| مكان الاستخدام | داخل دوال معالجة الأحداث (Event Handlers) والـ Effects | داخل شجرة التوجيه مباشرة كغلاف للمسارات المباشرة (Route Element) |
| الأثر التفاعلي | تنقل سلس وسريع بحسب منطق الشروط البرمجية في الصفحة | حماية صارمة ومباشرة للشاشة قبل رسم أي عنصر حساس بالـ DOM |
في التطبيقات الحقيقية، هناك صفحات لا ينبغي للعامة رؤيتها إلا بعد تسجيل الدخول (مثل: لوحة التحكم Admin Dashboard، صفحة إعدادات الحساب، أو الكورسات المشتراة).
نحتاج لميزتين رئيسيتين:
يُستخدم هوك useNavigate عندما نريد الانتقال لصفحة جديدة من داخل كود دالة (وليس بالضغط على رابط <Link>):
| 1 | import { useNavigate } from 'react'; |
| 2 | |
| 3 | function LoginForm() { |
| 4 | const navigate = useNavigate(); |
| 5 | |
| 6 | const handleLogin = (e) => { |
| 7 | e.preventDefault(); |
| 8 | // 1. منطق تسجيل الدخول |
| 9 | console.log('تم تسجيل الدخول بنجاح'); |
| 10 | |
| 11 | // 2. التوجيه البرمجي لصفحة الكورسات بعد النجاح |
| 12 | navigate('/courses'); |
| 13 | }; |
| 14 | |
| 15 | return <button onClick={handleLogin}>تسجيل الدخول</button>; |
| 16 | } |
لنمنع المستخدم غير المسجل من فتح صفحات معينة، ننشئ مكوناً غلافاً (Wrapper) يفحص حالة التسجيل:
| 1 | import { Navigate } from 'react'; |
| 2 | |
| 3 | // مكون حماية يأخذ الابناء (الصفحة المراد حمايتها) |
| 4 | function ProtectedRoute({ isAuthenticated, children }) { |
| 5 | if (!isAuthenticated) { |
| 6 | // إعادة تحويل فورية لصفحة التسجيل لو لم يكن مسجلاً |
| 7 | return <Navigate to="/login" replace />; |
| 8 | } |
| 9 | |
| 10 | return children; // عرض الصفحة بسلام لو كان مسجلاً |
| 11 | } |
الآن نغلف أي صفحة خاصة بـ ProtectedRoute داخل App.jsx:
App.jsx
| 1 | import { Routes, Route } from 'react-router-dom'; |
| 2 | |
| 3 | function App() { |
| 4 | const isAuth = false; // يتم جلبها عادة من Auth Context |
| 5 | |
| 6 | return ( |
| 7 | <Routes> |
| 8 | <Route path="/login" element={<LoginPage />} /> |
| 9 | |
| 10 | {/* حماية صفحة لوحة التحكم */} |
| 11 | <Route |
| 12 | path="/dashboard" |
| 13 | element={ |
| 14 | <ProtectedRoute isAuthenticated={isAuth}> |
| 15 | <DashboardPage /> |
| 16 | </ProtectedRoute> |
| 17 | } |
| 18 | /> |
| 19 | </Routes> |
| 20 | ); |
| 21 | } |
ℹ️ معلومة
عند إعادة توجيه الزائر غير المصرح له عبر <Navigate replace to="/login"/> أو navigate('/login', { replace: true }): تأكد دائماً من إضافة الخاصية replace
بدونه، سيقوم المتصفح بإضافة صفحة المحاولة الفاشلة إلى سجل التاريخ (History Stack). عندما يضغط المستخدم على زر "الرجوع" في المتصفح، سيعود للصفحة المحمية لتقوم بإرجاعه مجدداً للتسجيل، فيدخل في حلقة تكرارية مزعجة (Navigation Loop) ينسد معها زر الرجوع بالمناسبة