الگوهای ناوبری ضروری با React Router نسخه ۶ را کاوش کنید. مسیریابی اعلانی، مسیرهای پویا، ناوبری برنامهریزیشده، مسیرهای تودرتو و استراتژیهای بارگذاری داده را برای ساخت اپلیکیشنهای وب قدرتمند و کاربرپسند بیاموزید.
React Router نسخه ۶: تسلط بر الگوهای ناوبری برای اپلیکیشنهای وب مدرن
React Router نسخه ۶ یک کتابخانه مسیریابی قدرتمند و انعطافپذیر برای اپلیکیشنهای ریاکت است. این کتابخانه به شما امکان میدهد تا با مدیریت ناوبری بدون بارگذاری مجدد کامل صفحه، اپلیکیشنهای تکصفحهای (SPA) با تجربهی کاربری یکپارچه ایجاد کنید. این پست وبلاگ به بررسی الگوهای ناوبری ضروری با استفاده از React Router نسخه ۶ میپردازد و دانش و مثالهای لازم برای ساخت اپلیکیشنهای وب قدرتمند و کاربرپسند را در اختیار شما قرار میدهد.
درک مفاهیم اصلی React Router نسخه ۶
قبل از پرداختن به الگوهای خاص، بیایید برخی از مفاهیم بنیادی را مرور کنیم:
- مسیریابی اعلانی (Declarative Routing): React Router از یک رویکرد اعلانی استفاده میکند، که در آن شما مسیرهای خود را به عنوان کامپوننتهای ریاکت تعریف میکنید. این کار منطق مسیریابی شما را واضح و قابل نگهداری میکند.
- کامپوننتها: کامپوننتهای اصلی شامل
BrowserRouter
،HashRouter
،MemoryRouter
،Routes
وRoute
هستند. - هوکها (Hooks): React Router هوکهایی مانند
useNavigate
،useLocation
،useParams
وuseRoutes
را برای دسترسی به اطلاعات مسیریابی و دستکاری ناوبری فراهم میکند.
۱. مسیریابی اعلانی با <Routes>
و <Route>
پایه و اساس React Router نسخه ۶ بر مسیریابی اعلانی استوار است. شما مسیرهای خود را با استفاده از کامپوننتهای <Routes>
و <Route>
تعریف میکنید. کامپوننت <Routes>
به عنوان یک کانتینر برای مسیرهای شما عمل میکند و کامپوننت <Route>
یک مسیر خاص و کامپوننتی که باید هنگام تطابق آن مسیر با URL فعلی رندر شود را تعریف میکند.
مثال: پیکربندی اولیه مسیرها
در اینجا یک مثال ساده از تنظیم مسیرها برای یک اپلیکیشن ساده آورده شده است:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";
function App() {
return (
} />
} />
} />
);
}
export default App;
در این مثال، ما سه مسیر تعریف میکنیم:
/
: کامپوننتHome
را رندر میکند./about
: کامپوننتAbout
را رندر میکند./contact
: کامپوننتContact
را رندر میکند.
کامپوننت BrowserRouter
مسیریابی مبتنی بر تاریخچه مرورگر را فعال میکند. React Router URL فعلی را با مسیرهای تعریفشده تطبیق داده و کامپوننت مربوطه را رندر میکند.
۲. مسیرهای پویا با پارامترهای URL
مسیرهای پویا به شما امکان میدهند مسیرهایی ایجاد کنید که بتوانند مقادیر مختلفی را در URL مدیریت کنند. این برای نمایش محتوا بر اساس یک شناسه منحصر به فرد، مانند شناسه محصول یا شناسه کاربر، مفید است. React Router نسخه ۶ از نماد :
برای تعریف پارامترهای URL استفاده میکند.
مثال: نمایش جزئیات محصول
فرض کنید یک اپلیکیشن تجارت الکترونیک دارید و میخواهید جزئیات هر محصول را بر اساس شناسه آن نمایش دهید. میتوانید یک مسیر پویا مانند این تعریف کنید:
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom";
function ProductDetails() {
const { productId } = useParams();
// دریافت جزئیات محصول بر اساس شناسه محصول
// ...
return (
جزئیات محصول
شناسه محصول: {productId}
{/* نمایش جزئیات محصول در اینجا */}
);
}
function App() {
return (
} />
);
}
export default App;
در این مثال:
/products/:productId
یک مسیر پویا را تعریف میکند که در آن:productId
یک پارامتر URL است.- هوک
useParams
برای دسترسی به مقدار پارامترproductId
در کامپوننتProductDetails
استفاده میشود. - سپس میتوانید از
productId
برای دریافت جزئیات محصول مربوطه از منبع داده خود استفاده کنید.
مثال بینالمللیسازی: مدیریت کدهای زبان
برای یک وبسایت چندزبانه، ممکن است از یک مسیر پویا برای مدیریت کدهای زبان استفاده کنید:
} />
این مسیر با URLهایی مانند /en/about
، /fa/about
و /es/about
مطابقت دارد. سپس پارامتر lang
میتواند برای بارگذاری منابع زبان مناسب استفاده شود.
۳. ناوبری برنامهریزیشده با useNavigate
در حالی که مسیریابی اعلانی برای لینکهای ثابت عالی است، شما اغلب نیاز دارید که بر اساس اقدامات کاربر یا منطق اپلیکیشن به صورت برنامهریزیشده ناوبری کنید. React Router نسخه ۶ هوک useNavigate
را برای این منظور فراهم میکند. useNavigate
تابعی را برمیگرداند که به شما امکان میدهد به مسیرهای مختلف ناوبری کنید.
مثال: هدایت کاربر پس از ارسال فرم
فرض کنید یک فرم دارید و میخواهید پس از ارسال موفقیتآمیز فرم، کاربر را به صفحه موفقیت هدایت کنید:
import { useNavigate } from "react-router-dom";
function MyForm() {
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
// ارسال دادههای فرم
// ...
// هدایت به صفحه موفقیت پس از ارسال موفقیتآمیز
navigate("/success");
};
return (
);
}
export default MyForm;
در این مثال:
- ما از هوک
useNavigate
برای دریافت تابعnavigate
استفاده میکنیم. - پس از ارسال موفقیتآمیز فرم، ما
navigate("/success")
را فراخوانی میکنیم تا کاربر را به مسیر/success
هدایت کنیم.
ارسال State در حین ناوبری
شما همچنین میتوانید با استفاده از آرگومان دوم navigate
، state را به همراه ناوبری ارسال کنید:
navigate("/confirmation", { state: { orderId: "12345" } });
این کار به شما امکان میدهد دادهها را به کامپوننت مقصد منتقل کنید، که میتوان با استفاده از هوک useLocation
به آن دسترسی داشت.
۴. مسیرهای تودرتو و لایهها (Layouts)
مسیرهای تودرتو به شما امکان میدهند ساختارهای مسیریابی سلسلهمراتبی ایجاد کنید، جایی که یک مسیر درون مسیر دیگری قرار میگیرد. این برای سازماندهی اپلیکیشنهای پیچیده با چندین سطح ناوبری مفید است. این به ایجاد لایههایی کمک میکند که در آن عناصر خاصی از رابط کاربری به طور مداوم در بخشی از اپلیکیشن حضور دارند.
مثال: بخش پروفایل کاربری
فرض کنید یک بخش پروفایل کاربری با مسیرهای تودرتو برای نمایش اطلاعات پروفایل، تنظیمات و سفارشات کاربر دارید:
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function Profile() {
return (
پروفایل کاربری
-
اطلاعات پروفایل
-
تنظیمات
-
سفارشات
} />
} />
} />
);
}
function ProfileInformation() {
return کامپوننت اطلاعات پروفایل
;
}
function Settings() {
return کامپوننت تنظیمات
;
}
function Orders() {
return کامپوننت سفارشات
;
}
function App() {
return (
} />
);
}
export default App;
در این مثال:
- مسیر
/profile/*
با هر URL که با/profile
شروع شود، مطابقت دارد. - کامپوننت
Profile
یک منوی ناوبری و یک کامپوننت<Routes>
برای مدیریت مسیرهای تودرتو رندر میکند. - مسیرهای تودرتو کامپوننتهایی را که باید برای
/profile/info
،/profile/settings
و/profile/orders
رندر شوند، تعریف میکنند.
نماد *
در مسیر والد بسیار مهم است؛ این نشان میدهد که مسیر والد باید با هر زیرمسیری مطابقت داشته باشد، و به مسیرهای تودرتو اجازه میدهد تا به درستی درون کامپوننت Profile
مطابقت داده شوند.
۵. مدیریت خطاهای "پیدا نشد" (۴۰۴)
مدیریت مواردی که کاربر به مسیری که وجود ندارد میرود، ضروری است. React Router نسخه ۶ این کار را با یک مسیر catch-all (فراگیر) آسان میکند.
مثال: پیادهسازی صفحه ۴۰۴
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function NotFound() {
return (
۴۰۴ - پیدا نشد
صفحهای که به دنبال آن هستید وجود ندارد.
بازگشت به صفحه اصلی
);
}
function App() {
return (
} />
} />
} />
);
}
در این مثال:
- مسیر
<Route path="*" element={<NotFound />} />
یک مسیر فراگیر است که با هر URL که با هیچ یک از مسیرهای تعریفشده دیگر مطابقت ندارد، مطابقت مییابد. - مهم است که این مسیر را در انتهای کامپوننت
<Routes>
قرار دهید تا فقط در صورتی که هیچ مسیر دیگری مطابقت نداشته باشد، فعال شود.
۶. استراتژیهای بارگذاری داده با React Router نسخه ۶
React Router نسخه ۶ مکانیزمهای داخلی بارگذاری داده مانند نسخه قبلی خود (React Router v5 با `useRouteMatch`) را شامل نمیشود. با این حال، ابزارهایی را برای پیادهسازی موثر استراتژیهای مختلف بارگذاری داده فراهم میکند.
گزینه ۱: دریافت داده در کامپوننتها
سادهترین رویکرد، دریافت داده به طور مستقیم در کامپوننتی است که مسیر را رندر میکند. شما میتوانید از هوک useEffect
برای دریافت داده هنگام mount شدن کامپوننت یا هنگام تغییر پارامترهای URL استفاده کنید.
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
function ProductDetails() {
const { productId } = useParams();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchProduct() {
try {
const response = await fetch(`/api/products/${productId}`);
if (!response.ok) {
throw new Error(`خطای HTTP! وضعیت: ${response.status}`);
}
const data = await response.json();
setProduct(data);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchProduct();
}, [productId]);
if (loading) return در حال بارگذاری...
;
if (error) return خطا: {error.message}
;
if (!product) return محصول پیدا نشد
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
این رویکرد ساده است اما اگر نیاز به دریافت داده در چندین کامپوننت داشته باشید، میتواند منجر به تکرار کد شود. همچنین کارایی کمتری دارد زیرا دریافت داده تنها پس از mount شدن کامپوننت شروع میشود.
گزینه ۲: استفاده از یک هوک سفارشی برای دریافت داده
برای کاهش تکرار کد، میتوانید یک هوک سفارشی ایجاد کنید که منطق دریافت داده را در خود کپسوله کند. این هوک سپس میتواند در چندین کامپوننت استفاده مجدد شود.
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`خطای HTTP! وضعیت: ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
سپس، میتوانید از این هوک در کامپوننتهای خود استفاده کنید:
import { useParams } from "react-router-dom";
import useFetch from "./useFetch";
function ProductDetails() {
const { productId } = useParams();
const { data: product, loading, error } = useFetch(`/api/products/${productId}`);
if (loading) return در حال بارگذاری...
;
if (error) return خطا: {error.message}
;
if (!product) return محصول پیدا نشد
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
گزینه ۳: استفاده از یک کتابخانه مسیریابی با قابلیتهای دریافت داده (TanStack Router, Remix)
کتابخانههایی مانند TanStack Router و Remix مکانیزمهای داخلی دریافت داده را ارائه میدهند که به طور یکپارچه با مسیریابی ادغام میشوند. این کتابخانهها اغلب ویژگیهایی مانند موارد زیر را فراهم میکنند:
- Loaders: توابعی که *قبل* از رندر شدن یک مسیر اجرا میشوند و به شما امکان میدهند دادهها را دریافت کرده و به کامپوننت منتقل کنید.
- Actions: توابعی که ارسال فرمها و تغییرات داده را مدیریت میکنند.
استفاده از چنین کتابخانهای میتواند بارگذاری داده را به شدت ساده کرده و عملکرد را بهبود بخشد، به خصوص برای اپلیکیشنهای پیچیده.
رندر سمت سرور (SSR) و تولید سایت استاتیک (SSG)
برای بهبود سئو و عملکرد بارگذاری اولیه، استفاده از SSR یا SSG را با فریمورکهایی مانند Next.js یا Gatsby در نظر بگیرید. این فریمورکها به شما امکان میدهند دادهها را در سرور یا در زمان بیلد دریافت کرده و HTML از پیش رندر شده را به کلاینت ارائه دهید. این کار نیاز کلاینت به دریافت داده در بارگذاری اولیه را از بین میبرد و منجر به تجربهای سریعتر و سازگارتر با سئو میشود.
۷. کار با انواع مختلف روتر
React Router نسخه ۶ پیادهسازیهای مختلف روتر را برای سازگاری با محیطها و موارد استفاده گوناگون فراهم میکند:
- BrowserRouter: از HTML5 history API (
pushState
,replaceState
) برای ناوبری استفاده میکند. این رایجترین انتخاب برای اپلیکیشنهای وب است که در محیط مرورگر اجرا میشوند. - HashRouter: از بخش هش URL (
#
) برای ناوبری استفاده میکند. این برای اپلیکیشنهایی که نیاز به پشتیبانی از مرورگرهای قدیمیتر دارند یا روی سرورهایی مستقر شدهاند که از HTML5 history API پشتیبانی نمیکنند، مفید است. - MemoryRouter: تاریخچه "URL" شما را در حافظه (آرایهای از URLها) نگه میدارد. این برای محیطهایی مانند React Native و تستنویسی مفید است.
نوع روتری را انتخاب کنید که به بهترین شکل با نیازمندیها و محیط اپلیکیشن شما سازگار باشد.
نتیجهگیری
React Router نسخه ۶ یک راهحل مسیریابی جامع و انعطافپذیر برای اپلیکیشنهای ریاکت فراهم میکند. با درک و به کارگیری الگوهای ناوبری که در این پست وبلاگ مورد بحث قرار گرفت، میتوانید اپلیکیشنهای وب قدرتمند، کاربرپسند و قابل نگهداری بسازید. از مسیریابی اعلانی با <Routes>
و <Route>
گرفته تا مسیرهای پویا با پارامترهای URL، ناوبری برنامهریزیشده با useNavigate
، و استراتژیهای موثر بارگذاری داده، React Router نسخه ۶ شما را برای ایجاد تجربیات ناوبری یکپارچه برای کاربران خود توانمند میسازد. برای کنترل بیشتر و بهینهسازی عملکرد، کاوش در کتابخانههای مسیریابی پیشرفته و فریمورکهای SSR/SSG را در نظر بگیرید. به یاد داشته باشید که این الگوها را با نیازمندیهای خاص اپلیکیشن خود تطبیق دهید و همیشه یک تجربه کاربری واضح و شهودی را در اولویت قرار دهید.