برپایی پیشنیازها
ابتدا کتابخانهی react-router-dom را نصب میکنیم:
npm i react-router-dom --save
import { BrowserRouter } from "react-router-dom"; //... ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById("root") );
برای تکمیل نیازمندیهایی که در مقدمه عنوان شد، این کامپوننتهای جدید را ایجاد میکنیم:
کامپوننت بدون حالت تابعی src\components\customers.jsx با این محتوا:
import React from "react"; const Customers = () => { return <h1>Customers</h1>; }; export default Customers;
کامپوننت بدون حالت تابعی src\components\rentals.jsx با این محتوا:
import React from "react"; const Rentals = () => { return <h1>Rentals</h1>; }; export default Rentals;
کامپوننت بدون حالت تابعی src\components\notFound.jsx با این محتوا:
import React from "react"; const NotFound = () => { return <h1>Not Found</h1>; }; export default NotFound;
کامپوننت بدون حالت تابعی src\components\movieForm.jsx با این محتوا:
import React from "react"; const MovieForm = () => { return ( <div> <h1>Movie Form</h1> <button className="btn btn-primary">Save</button> </div> ); }; export default MovieForm;
ثبت مسیریابیهای مورد نیاز برنامه
پس از نصب کتابخانهی مسیریابی و راه اندازی آن، اکنون نوبت به تعریف مسیریابیهای مورد نیاز برنامه در فایل app.js است:
import "./App.css"; import React from "react"; import { Redirect, Route, Switch } from "react-router-dom"; import Customers from "./components/customers"; import Movies from "./components/movies"; import NotFound from "./components/notFound"; import Rentals from "./components/rentals"; function App() { return ( <main className="container"> <Switch> <Route path="/movies" component={Movies} /> <Route path="/customers" component={Customers} /> <Route path="/rentals" component={Rentals} /> <Route path="/not-found" component={NotFound} /> <Redirect to="/not-found" /> </Switch> </main> ); } export default App;
تا اینجا اگر برنامه را اجرا کنیم، بلافاصله به http://localhost:3000/not-found هدایت میشویم. از این جهت که هنوز مسیریابی را برای / یا ریشهی سایت که در ابتدا نمایش داده میشود، تنظیم نکردهایم. به همین جهت Redirect زیر را پیش از آخرین Redirect تعریف شده اضافه میکنیم تا با درخواست ریشهی سایت، به آدرس /movies هدایت شویم:
<Redirect from="/" to="/movies" />
<Redirect from="/" exact to="/movies" />
افزودن منوی راهبری به برنامه
ابتدا فایل جدید src\components\navBar.jsx را ایجاد میکنیم؛ با این محتوا:
import React from "react"; import { Link, NavLink } from "react-router-dom"; const NavBar = () => { return ( <nav className="navbar navbar-expand-lg navbar-light bg-light"> <Link className="navbar-brand" to="/"> Home </Link> <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation" > <span className="navbar-toggler-icon" /> </button> <div className="collapse navbar-collapse" id="navbarNavAltMarkup"> <div className="navbar-nav"> <NavLink className="nav-item nav-link" to="/movies"> Movies </NavLink> <NavLink className="nav-item nav-link" to="/customers"> Customers </NavLink> <NavLink className="nav-item nav-link" to="/rentals"> Rentals </NavLink> </div> </div> </nav> ); }; export default NavBar;
- ساختار کلی NavBar ای را که ملاحظه میکنید، دقیقا از مثالهای رسمی مستندات بوت استرپ 4 گرفته شدهاست و تمام classهای آن با className جایگزین شدهاند.
- سپس تمام anchorهای موجود در یک منوی راهبری بوت استرپ را به Link و یا NavLink تبدیل کردهایم تا برنامه به صورت SPA عمل کند؛ یعنی با کلیک بر روی هر لینک، بارگذاری کامل صفحه در مرورگر صورت نگیرد و تنها محل و قسمتی که توسط کامپوننتهای Route مشخص شده، به روز رسانی شوند. تفاوت NavLink با Link در کتابخانهی react-router-dom، افزودن خودکار کلاس active به المانی است که بر روی آن کلیک شدهاست. به این ترتیب بهتر میتوان تشخیص داد که هم اکنون در کجای منوی راهبری قرار داریم.
- پس از تبدیل anchorها به Link و یا NavLink، مرحلهی بعد، تبدیل hrefهای لینکهای قبلی به ویژگی to است که هر کدام باید به یکی از مسیریابیهای تنظیم شده، مقدار دهی گردد.
پس از تعریف کامپوننت منوی راهبری سایت، به app.js بازگشته و این کامپوننت را پیش از مسیریابیهای تعریف شده اضافه میکنیم:
import NavBar from "./components/navBar"; // ... function App() { return ( <React.Fragment> <NavBar /> <main className="container"> // ... </main> </React.Fragment> ); } export default App;
به علاوه به فایل index.css برنامه مراجعه کرده و padding این navBar را صفر میکنیم تا از بالای صفحه و بدون فاصلهای نمایش داده شود و container اصلی نیز اندکی از پایین آن فاصله پیدا کند:
body { margin: 0; padding: 0 0 0 0; font-family: sans-serif; } .navbar { margin-bottom: 30px; } .clickable { cursor: pointer; }
اگر دقت کنید چون آدرس http://localhost:3000/movies در حال نمایش است، در منوی راهبری، گزینهی متناظر با آن، با رنگی دیگر مشخص (فعال) شدهاست.
لینک کردن عناوین فیلمهای نمایش داده شده به کامپوننت movieForm
برای تبدیل عناوین نمایش داده شدهی در جدول فیلمها به لینک، به کامپوننت src\components\moviesTable.jsx مراجعه کرده و تغییرات زیر را اعمال میکنیم:
- در قدم اول باید بجای ذکر خاصیت Title در آرایهی ستونهای جدول:
class MoviesTable extends Component { columns = [ { path: "title", label: "Title" },
class MoviesTable extends Component { columns = [ { path: "title", label: "Title", content: movie => <Link to={`/movies/${movie._id}`}>{movie.title}</Link> },
همچنین این Link را هم باید در بالای این ماژول import کرد:
import { Link } from "react-router-dom";
تعریف مسیریابی نمایش جزئیات یک فیلم انتخابی
اگر به تصویر فوق دقت کنید، به آدرسهایی مانند http://localhost:3000/movies/5b21ca3eeb7f6fbccd47181a رسیدهایم که به همراه id هر فیلم هستند. اکنون میخواهیم کلیک بر روی این لینکها را جهت فعالسازی صفحهی نمایش جزئیات فیلم، تنظیم کنیم. به همین جهت به فایل app.js مراجعه کرده و مسیریابی زیر را به ابتدای Switch تعریف شده اضافه میکنیم:
<Route path="/movies/:id" component={MovieForm} />
import MovieForm from "./components/movieForm";
تکمیل کامپوننت نمایش جزئیات یک فیلم
اکنون میخواهیم صفحهی نمایش جزئیات فیلم، به همراه نمایش id فیلم باشد و همچنین با کلیک بر روی دکمهی Save آن، کاربر را به صفحهی movies هدایت کند. به همین جهت فایل src\components\movieForm.jsx را به صورت زیر ویرایش میکنیم:
import React from "react"; const MovieForm = ({ match, history }) => { return ( <div> <h1>Movie Form {match.params.id} </h1> <button className="btn btn-primary" onClick={() => history.push("/movies")} > Save </button> </div> ); }; export default MovieForm;
- چون این کامپوننت، یک کامپوننت تابعی بدون حالت است، props را باید از طریق آرگومان خود دریافت کند و البته در همینجا امکان Object Destructuring خواصی که از آن نیاز داریم، مهیا است؛ مانند { match, history } که ملاحظه میکنید.
- سپس شیء match، امکان دسترسی به params ارسالی به صفحه را مانند id فیلم، میسر میکند.
- با استفاده از شیء history و متد push آن میتوان علاوه بر به روز رسانی تاریخچهی مرورگر، به مسیر مشخص شده بازگشت که در همینجا و به صورت inline، تعریف شدهاست.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: sample-17.zip