شرح استخدام react-router-dom في React مع تطبيق عملي على عرض المنتجات وتفاصيلها
عند بناء تطبيق باستخدام React، نحتاج إلى نظام تنقل يسمح بالانتقال بين الصفحات بدون إعادة تحميل الصفحة. هنا تأتي مكتبة react-router-dom التي تعتبر الحل الأساسي لإدارة التنقل داخل تطبيقات React الحديثة.
في هذا المقال سنطبق مثال عملي يعرض قائمة منتجات، ثم الانتقال إلى صفحة تفاصيل كل منتج، مع شرح كامل لكل صفحة مستخدمة في المشروع.
الصفحة الأولى: main.jsx
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.bundle.min.js'
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App.jsx'
import './index.css'
createRoot(document.getElementById('root')).render(
,
)
شرح الصفحة
هذه الصفحة هي نقطة تشغيل التطبيق. تم استخدام BrowserRouter لتفعيل نظام التنقل داخل التطبيق، حيث يسمح باستخدام الروابط والمسارات بدون إعادة تحميل الصفحة.
كما تم استيراد Bootstrap لتنسيق الواجهة، واستخدام StrictMode للمساعدة في اكتشاف الأخطاء أثناء التطوير.
الصفحة الثانية: App.jsx
import { Route, Routes } from 'react-router-dom';
import Navbar from './componants/componants/Navbar';
import ProductList from './componants/componants/ProductList';
import Slider from './componants/componants/Slider';
import ProductDetail from './componants/ProductDetail';
function App() {
return (
<>
```
<Routes>
<Route
path="/"
element={
<>
<Slider />
<ProductList />
</>
}
/>
<Route
path="/products/:prodId"
element={<ProductDetail />}
/>
</Routes>
</>
```
)
}
export default App;
شرح الصفحة
هذه الصفحة مسؤولة عن تعريف المسارات داخل التطبيق. تم استخدام Routes لتحديد أي مكون يتم عرضه حسب الرابط.
- المسار
/يعرض الصفحة الرئيسية (Slider + ProductList) - المسار
/products/:prodIdيعرض صفحة تفاصيل المنتج
تم استخدام المسار الديناميكي :prodId لتمكين عرض أي منتج باستخدام نفس الصفحة.
كما أن Navbar تم وضعه خارج Routes لأنه يظهر في جميع الصفحات.
الصفحة الثالثة: ProductDetail.jsx
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import ProductItem from "./componants/Product";
import { useNavigate } from "react-router-dom";
function ProductDetail(props) {
const prodId = useParams().prodId;
const baseURL = "[https://fakestoreapi.com](https://fakestoreapi.com/)";
const [product, setProduct] = useState({});
const navigate = useNavigate();
```
useEffect(() => {
fetch(`${baseURL}/products/${prodId}`)
.then((res) => res.json())
.then((data) => setProduct(data));
}, []);
return (
<div>
<div className="container mt-5">
<h1>Product Detail</h1>
<ProductItem
product={product}
showButton={false}
allData={true}
/>
<button
className="btn btn-primary mb-3 w-100"
onClick={() => navigate(-1)}
>
Go Back
</button>
</div>
</div>
)
```
}
export default ProductDetail;
شرح الصفحة
هذه الصفحة مسؤولة عن عرض تفاصيل منتج واحد. يتم قراءة رقم المنتج من الرابط باستخدام useParams، ثم يتم جلب بيانات المنتج من API.
بعد جلب البيانات، يتم عرضها باستخدام مكون ProductItem.
تم أيضًا استخدام useNavigate لإضافة زر “Go Back” الذي يسمح للمستخدم بالرجوع إلى الصفحة السابقة بسهولة.
الصفحة الرابعة: ProductItem.jsx
import { Link } from "react-router-dom";
function ProductItem({ product, showButton = true, allData = false }) {
return (
```
<img
src={product?.image}
style={{ height: "300px", objectFit: "contain" }}
className="card-img-top p-5"
alt={product?.title ? product.title : "Loading..."}
/>
<div className="card-body d-flex flex-column justify-content-between">
<h5 className="card-title">
{product?.title
? allData
? product.title
: product.title.substring(0, 15) + "..."
: "Loading..."}
</h5>
<p className="card-text">
{product?.description
? allData
? product.description
: product.description.substring(0, 100) + "..."
: "Loading..."}
</p>
{showButton && (
<Link to={`/products/${product.id}`} className="btn btn-primary">
View Details
</Link>
)}
</div>
</div>
```
);
}
export default ProductItem;
شرح الصفحة
هذا المكون مسؤول عن عرض المنتج داخل بطاقة. تم تصميمه ليكون قابل لإعادة الاستخدام.
- في الصفحة الرئيسية: يعرض بيانات مختصرة + زر انتقال
- في صفحة التفاصيل: يعرض البيانات كاملة بدون زر
تم استخدام Link للتنقل بين الصفحات بدون إعادة تحميل الصفحة.
مميزات التطبيق
- تنقل سريع بدون إعادة تحميل الصفحة
- استخدام مسارات ديناميكية
- إعادة استخدام المكونات
- فصل منطق البيانات عن العرض
- تجربة مستخدم سلسة
ملاحظات
- يفضل إضافة حالة تحميل (Loading)
- يفضل التعامل مع أخطاء API
- إضافة prodId داخل useEffect
الخلاصة
باستخدام react-router-dom يمكنك بناء تطبيق React احترافي يحتوي على صفحات متعددة وتنقل سلس. هذا المثال يوضح كيفية الربط بين الصفحات، واستخدام المسارات الديناميكية، وعرض البيانات بطريقة منظمة.
لمزيد من المقالات : MVI Architecture Pattern في Flutter: تحكم دقيق في تدفق البيانات وتجربة مستخدم تفاعلية






