آموزش React Router


در این مقاله قصد داریم نحوه جابجایی( navigational) بین کامپوننت ها در React رو با استفاده از کتابخانه React Router یاد بگیریم.مواردی که قراره در این مقاله پوشش بدیم :
- What React Router is
- Setting up your first routes
- The importance of using ‘Exact’
- 404 Component and Switch
- Links
- Navigation
- Rendering several components at once
- Nested routes
در این مقاله با استفاده از React Router به صورت کامل navigation رو پیاده خواهیم کرد.بنابراین اگر قصد دارید که با من همراه باشید code editor خود را باز کنید!
React Router چیست؟
React Router کتابخانه است که به شما این امکان را می دهد تا routes های خود را در frot-end مشخص کنید.بنابراین کاربران کامپوننت ها را در مسیرهایی مثل localhost:3000/homepage , localhost:3000/faq, /links, /contact و … میبینند.شما می توانید یک برنامه react ایجاد کنید اما اینکه با کلیک کردن بر روی آیکون چه کامپوننتی نمایش داده شود یا به چه صفحه ای منتقل شود، به شما مربوط است.
Setting up your first routes
در ابتدا 3 کامپوننت در فایل components.js در پوشه src ایجاد می کنیم که بعدا در route ها یا page های مختلف قرار میگیرند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import React from "react" const Homepage = () => { return "Welcome to my website about my pets." } const Dog = () => { return "My dog Thundric is great. I couldn’t decide between Thunder or Electric. Don’t call him Rick." } const Cat = () => { return "I love my cat Smalls. He sure is hefty." } export { Homepage, Dog, Cat } |
به زودی میتونیم به هر کامپوننت با آدرس های زیر دسترسی داشته باشیم:
localhost:3000
localhost:3000/dog
localhost:3000/cat
در ادامه یک فایل به نام routes.js در دایرکتوری src ایجاد و یک کامپوننت به نام Routes تعریف میکنیم.برای استفاده از کتابخانه React Router ما باید آن را نصب کنیم.بنابراین دایرکتوری پروژه رو در cmd باز می کنیم و دستور npm install react-router-dom رو اجرا می کنیم.
1 2 3 4 5 6 7 |
import React from "react" const Routes = () => { return <div></div> } export default Routes |
حالا نوبت به نوشتن route های برنامه است.برای اینکار باید Route را ایمپورت کنیم
1 |
import { Route } from "react-router-dom" |
سپس براب هر Route یک pathname و یک کامپوننت مشخص می کنیم.
1 |
<Route path="/path-name-goes-here" component={ComponentName} /> |
route های صفحات شما باید چیزی شبیه این باشد.ما یک attribute خیلی مهم به نام ‘exact’ در route مربوط به Homepage خود داریم که در ادامه در مورد آن صحبت خواهیم کرد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import React from "react" import { Route } from "react-router-dom" import { Homepage, Dog, Cat } from "./components" const Routes = () => { return ( <div> <Route exact path="/" component={Homepage} /> <Route path="/dog" component={Dog} /> <Route path="/cat" component={Cat} /> </div> ) } export default Routes |
حالا باید یک سری تغییرات در فایل index.js ایجاد کنیم.در تابع ReactDOM.render() به جای کامپوننت App از کامپوننت Routes استفاده میکنیم.فراموش نکنید که ابتدا Routes را ایمپورت کنیم.
همچنین نیاز به Router داریم تا route های خودمون رو درونش wrap کنیم.بنابراین باید اون رو از ‘react-router-dom’ ایمپورت کنیم.
در انتها برای اینکه بتوانیم navigation را track کنیم باید createHistory رو از ‘history/createBrowserHistory ایمپورت کنیم.()createHistory را به یک متغیر به نام history اختصاص می دهیم و به ‘history’ attribute در Router پاس می دهیم.
فایل index.js شما باید شبیه کدهای زیر باشد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import React from "react" import ReactDOM from "react-dom" import "./index.css" import Routes from "./routes" import { Router } from "react-router-dom" import createHistory from 'history/createBrowserHistory' import * as serviceWorker from "./serviceWorker" const history = createHistory() ReactDOM.render( <Router history={history}> <Routes /> </Router>, document.getElementById("root") ) serviceWorker.unregister() |
دستور npm start را اجرا کنید تا تغییراتی که ایجاد کردید رو ببینید.شما باید به کامپوننت ها از طریق آدرس های زیر دسترسی داشته باشید.
localhost:3000/
localhost:3000/dog
localhost:3000/cat
The importance of using exact
‘exact’ با اینکه فقط یک attribute است اما از اهمیت خیلی بالایی برخوردار است که در homepage Route ما از آن استفاده کردیم:
1 |
<Route exact path="/" component={Homepage} /> |
برای اینکه به اهمیت این attribute پی ببرید کافیه که اون رو حذف کنید و 3 تا مسیری که قبلا مشخص کردیم رو تست کنید و ببیند که چه اتفاقی افتاده است.
شما باید یک چیزی شبیه عکس زیر رو ببینید:
‘exact’این مشکل را حل می کند و اطمینان حاصل میکند تنها کامپوننتی را render کند دقیقا با آدرس وارد شده matche باشد.
‘Not Found’ 404 Component
منطق نحوه نمایش Route برای routes ها را دنبال کنید.میتونید حدس بزنید که چطور میشه یک کامپوننت page not found” را هر زمانی که یک pathname نامعتبر وارد شد،render کرد؟
کامپوننت خودمون رو تعریف میکنیم
1 2 3 4 5 |
const NotFound = () => { return "Page not found." } … export {NotFound } |
یک Route در فایل routes.js بدون path attribute اضافه می کنیم:
1 |
<Route component={NotFound} /> |
اخرین Route این مورد را قرار دهید تا زمانی که pathnames وارد شده توسط کاربر با هیچ کدام از Route های ما مطابقت نداشت،کامپوننت NotFound نمایش داده شود.
اما این کافی نیست.مهم ترین قسمت ایمپورت کردن Switch از ‘react-router-dom’ است.Switch این امکان را در اختیار ما می گذارد که تنها در هر زمان فقط یک کامپوننت را render کنیم.اگر ما از Switch استفاده نکنیم، 404 route همیشه در پایین صفحات نمایش داده خواهد شد.
فایل routes.js شما بعد از تغییرات باید شبیه کدهای زیر باشد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import React from "react" import { Route, Switch } from "react-router-dom" import { Homepage, Dog, Cat, NotFound } from "./components" const Routes = () => { return ( <div> <Switch> <Route exact path="/" component={Homepage} /> <Route path="/dog" component={Dog} /> <Route path="/cat" component={Cat} /> <Route component={NotFound} /> </Switch> </div> ) } export default Routes |
برای دیدن صفحه 404 یک آدرس اشتباه و نامعتبر را وارد کنید تا از عملکرد صحیح کدهای خودتون اطمینان حاصل کنید.
توجه داشته باشید که Switch جایگزین exact نیست.اگر شما ‘exact’ را از route مربوط به Homepage پاک کنید،کامپوننت های مربوط به dog/ و cat/ نمایش داده نخواهند شد.به سادگی در اولین pathname که با ورودی کاربر مطابقت داشته باشد متوقف خواهیم شد.بنابراین برای dog/ و cat/ در ‘/’ متوقف می شویم.
Links in React Router
حالا نوبت به این میرسه که یکم تتبل تر بشیم و دیگه آدرس ها رو خودمون به صورت دستی وارد نکنیم بنابراین باید link ها رو در فایل components.js اضافه کنیم.
در components.js بیایید { Link } را از ‘react-router-dom’ ایمپورت کنید و یک link با فرمت زیر برای نمایش dog و cat بنویسید
1 |
<Link to="/pathname">Click here</Link> |
کامپوننت Homepage شما باید به شکل زیر باشد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const Homepage = () => { return ( <div> <p>Welcome to my website about my pets.</p> <ul> <li> <Link to="/dog">My Dog</Link> </li> <li> <Link to="/cat">My Cat</Link> </li> </ul> </div> ) } |
Navigation
ما به button های back و forward مرورگر برای برگشتن به homepage نیاز نداریم.ما میتوانیم خیلی راحت button هایی برای back و forward به کامپوننت های Dog و Cat ایجاد کنیم.
شما می توانید history object را به عنوان آرایه ای که شامل indexes هایی از صفحات که ما رفته ایم که نشان می دهد از نظر back و forward کجا هستیم،، در نظر بگیرید.شما میتوانید کاربر رو در اخرین آبتم آرایه در نظر بگیرید.زمانی که کاربر قصد دارد ‘back’ را انجام بدهد،در واقع به آیتم یکی به آخر آرایه انتقال پیدا می کند.
دکمه ای که بدون در نظر گرفتن اینکه از کجا آمده ایم ، یک گام ما را برمی گرداند،شبیه زیر است:
1 2 3 4 5 6 7 8 9 10 11 12 |
const Dog = props => { return ( <div> <p> My dog Thundric is great. I couldn’t decide between Thunder or Electric. Don’t call him Rick. </p> <p> <button onClick={() => props.history.goBack()}>Back</button> </p> </div> ) } |
یک forward button شبیه زیر است:
1 |
<button onClick={() => props.history.goForward()}>Forward</button> |
اگر بخواهیم N گام forward یا backward انجام دهیم،باید شبیه زیر عمل کنیم:
1 |
<button onClick={() => props.history.go(-2)}>Back two pages</button> |
ما حتی می توانیم یک دکمه home اضافه کنیم که Homepage را به nc”آرایه” ما وارد می کند و ما را به آنجا می ببرد:
1 |
<button onClick={() => props.history.push("/")}>Home</button> |
Rendering several components at once (Nav bar style)
ممکن است شما قصد نداشته باشید که با کلیک کردن کل webpage شما متقل شود.ساده ترین مثال رو میتونید header برنامتون در نظر بگیرید که باید در تمامی صفحات ثابت باشد.پس از این نوع از route ها غافل نشوید.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const Routes = () => { return ( <div> <p>Hi there! This text stays put, and the other components rotate below.</p> <Switch> <Route exact path="/" component={Homepage} /> <Route path="/dog" component={Dog} /> <Route path="/cat" component={Cat} /> <Route component={NotFound} /> </Switch> </div> ) } |
بهترین مکان برای قرار دادن header خارج از switch است چون با جابجایی بین صفحات ثابت می ماند
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const Routes = () => { return ( <div> <Link to="/">Homepage</Link> {/*...etc*/} <Switch> <Route exact path="/" component={Homepage} /> <Route path="/dog" component={Dog} /> <Route path="/cat" component={Cat} /> <Route component={NotFound} /> </Switch> </div> ) } |
Nested Routes
تا اینجا ما بحث react router رو در قالب یک وب سایت حیوانات خانگی پیش میبردیم(به علت داشتن dog و cat).حالا تصور کنید که قصد داریم فیلد کاری خودمان را عوض کنیم و یک وب سایت سنگ های قیمتی داشته باشیم.در این وب سایت ما بیش از 1000 نوع سنگ قیمتی داریم که اگر بخوایم اطلاعات هر کدام را نشان دهیم.منطقی ترین راه استفاده از یک کامپوننت است. اما React Router چگونه به ما کمک می کند؟
فرض کنید که ما قصد داشته باشیم اطلاعات هر کدام را در یک کامپوننت جداگانه داشته باشیم.یک کابوس بزرگ خواهد بود:
1 2 3 4 5 6 7 8 9 10 |
const Routes = () => { return ( <Switch> <Route path="/marble/1" component={Marble} /> <Route path="/marble/2" component={Marble} /> <Route path="/marble/3" component={Marble} /> ... </Switch> ) } |
به جای اینکار می توانیم از ویژگی params استفاده کنیم:
1 2 3 4 5 6 7 8 |
const Routes = () => { return ( <Switch> <Route path="/marble/:id" component={Marble} /> <Route component={NotFound} /> </Switch> ) } |
شگفت انگیز است! اما کامپوننت چگونه تشخیص دهد که اطلاعات کدام سنگ را نمایش دهد؟
بهتر است که یک نگاهی به کامپوننت Marble بندازیم
1 2 3 |
const Marble = props => { return <div>This is Marble number {props.match.params.id}!</div> } |
با استفاده از ‘props.match.params’ ما میتوانیم به پارامترهای URL دسترسی داشته باشیم و با استفاده از ID بدست اومده کامپوننت تشخیص میده که اطلاعات کدوم سنگ رو نمایش بده.
اگر کاربر بر روی لینکی کلیک کنه مشابه زیر باشه:
localhost:3000/marble/241
کامپوننت عبارت “This is Marble number 241!” را render میکنه.
در قطعه کد پایین یک مثال کاملتر از کامپوننت Marble را داریم که ID را به کاربر نمایش نمیده و به جای اون یک درخواست به سرور میزنه و اطلاعات مربوط به ID قرار گرفته در URL رو از دیتابیس میگیره.این یک استفاده خیلی پویاتر از params ها است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Marble extends Component { constructor() { super() this.state= { color: "", millimeters: 0 } } async componentDidMount() { try { const res = await axios.get(`/marble/${this.props.match.params.id}`) const uniqueMarble = res.data this.setState({ color: uniqueMarble.color, millimeters: uniqueMarble.millimeters }) } catch (err) { console.error(err) } } render() { return <div> This is Marble number {this.props.match.params.id}! It's the color {this.state.color} and only {this.state.millimeters} millimeters small.</div> } |
این React Router است که قدرت و امکانات مختلفی را در اختیار ما میگذارد.امیدوارم از خوندن این مقاله لذت بریده باشید و براتون مفید واقع شده باشه.فراموش نکنید که اون رو با دوستاتون به اشتراک بزارید.
همچنین اگر قصد دارید به یک React Developer حرفه ای تبدیل بشید،پیشنهاد میکنم دوره آموزش جامع React Js رو مشاهده کنید.
مطالب زیر را حتما مطالعه کنید
ویژگی ها و قابلیت های جدید react 18
فریمورک های Frontend که باید در سال 2021 یاد بگیرید
نگاه اولیه به React Server Component
React Higher Order Components چیست
5 React Best Practice که باید در سال 2020 یاد بگیرید
Hook های مفیدی که باید در پروژه بعدی React خود از آن استفاده کنید
5 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
بسیار عالی
خیلی عالی و جامع و ساده و روان نوشته شده بود خیلی ممنون
ممنون از لطفتون
مرسی خیلی عالی بود
ممنون از لطفتون