اضافه کردن Routing به همبرگرساز

08 اسفند 1398
اضافه کردن Routing به همبرگر ساز

اضافه کردن Routing به همبرگرساز

در جلسه ی قبل صفحه ی Checkout را ساختیم و در این جلسه باید Routing را به آن اضافه کنیم. برای شروع باید پکیج react-router-dom را به پروژه ی خودمان اضافه کنیم. بنابراین در ترمینال خودمان می گوییم:

npm install --save react-router-dom

از فصل هشتم نیز یاد گرفتیم که برای استفاده از Routing باید برنامه را بین تگ های BrowserRouter قرار دهیم. من این کار را در index.js انجام می دهم (البته شما می توانید این کار را در App.js نیز انجام دهید). بنابراین به فایل index.js بروید و react-router-dom را به آن اضافه کنید:

import { BrowserRouter } from 'react-router-dom';

سپس یک ثابت به نام app و به شکل زیر می سازیم:

const app = (
    <BrowserRouter>
        <App />
    </BrowserRouter>
);

و به جای <App> همین ثابت را در render قرار می دهیم:

const app = (
    <BrowserRouter>
        <App />
    </BrowserRouter>
);

ReactDOM.render(app, document.getElementById('root'));

حالا وارد App.js شده و Route را وارد پروژه کنید:

import { Route } from 'react-router-dom';

سپس به جای استفاده از <BurgerBuilder> و <Checkout> به صورت دستی، از <Route> استفاده می کنم:

<Switch>
    <Route path="/checkout" component={Checkout} />
    <Route path="/" exact component={BurgerBuilder} />
</Switch>

همانطور که می بینید من هم از exact استفاده کرده ام و هم از <Switch> اما استفاده از یکی از آن ها کافی بود. من این کار را انجام داده ام تا شما بدانید هر دو روش کار می کنند. همچنین اگر از Switch استفاده می کنید باید مثل من آن را import کرده باشید:

import { Route, Switch } from 'react-router-dom';

در واقع اگر از exact استفاده می کنید ترتیب دو Route بالا مهم نیست اما اگر از Switch استفاده می کنید باید یادتان باشد که / همیشه پیشوند حساب می شود (در صورتی که exact نباشد) بنابراین باید همیشه آخر باشد. اگر Route مربوط به BurgerBuilder را اول قرار دهیم، در صفحه ی اصلی به آدرس / هر دو کامپوننت بارگذاری می شوند.

حالا اگر به مرورگر بروید مشاهده خواهید کرد که در صفحه ی اصلی فقط BurgerBuilder بارگذاری می شود. در مرحله ی بعد باید کاری کنیم که با کلیک روی CONTINUE صفحه ی checkout بارگذاری شود بنابراین به فایل BurgerBuilder.js می رویم تا ببینیم چه تابعی مسئول CONTINUE است:

orderSummary = <OrderSummary
    ingredients={this.state.ingredients}
    price={this.state.totalPrice}
    purchaseCancelled={this.purchaseCancelHandler}
    purchaseContinued={this.purchaseContinueHandler}
/>;

بنابراین با کلیک روی این دکمه، متد purchaseContinueHandler اجرا خواهد شد بنابراین باید به purchaseContinueHandler نگاهی می اندازیم:

purchaseContinueHandler = () => {
    // alert('You continue!')
    this.setState({ loading: true })
    const order = {
        ingredients: this.state.ingredients,
        price: this.state.totalPrice,
        customer: {
            name: 'Amir Zouerami',
            address: {
                street: 'Teststreet 1',
                zipCode: '9174582541',
                country: 'Iran'
            },
            email: 'test@test.com'
        },
        deliveryMethod: 'fastest'
    }
    axios.post('/orders.json', order)
        .then(response => {
            this.setState({ loading: false, purchasing: false });
        })
        .catch(error => {
            this.setState({ loading: false, purchasing: false });
        });
}

همانطور که می بینید این تابع ابتدا state را روی loading قرار می دهد و سپس اطلاعات ما را با axios به سمت Firebase ارسال می کند. من تمام کدهای داخل تابع purchaseContinueHandler را کامنت می کنم تا اجرا نشوند. نکته ی مهم اینجا این است که BurgerBuilder بخشی از BrowserRouter است بنابراین به تمام prop های match و history و... دسترسی دارد. برای ثابت کردن این موضوع می توانیم در همین فایل BurgerBuilder.js وارد componentDidMount شویم و دستور console.log زیر را به آن اضافه کنیم:

componentDidMount() {
    console.log(this.props);

حالا در مرورگر می بینیم:

prop های مربوط به routing در BurgerBuilder.js
prop های مربوط به routing در BurgerBuilder.js

اما مسئله اینجاست که Burger.js به این prop ها دسترسی ندارد چرا که توسط <Route> بارگذاری نشده است (فقط BurgerBuilder.js اینطور بارگذاری شده است). همانطور که قبلا گفته بودیم این prop ها به فرزندان به ارث نمی رسند بنابراین باید آن ها را به صورت دستی پاس بدهیم. البته روش پیشرفته ی دیگری نیز وجود دارد که prop های routing را به فرزندان پاس می دهد و من می خواهم این روش را به شما نشان دهم.

ابتدا وارد فایل Burger.js شوید و مثل من دستور console.log را اضافه کنید:

const burger = (props) => {
    console.log(props);
// بقیه ی کدها //

در حال حاضر در قسمت کنسول مرورگر این prop را نیز مشاهده می کنیم:

prop های فایل burger.js که شامل prop های routing نیستند.
prop های فایل burger.js که شامل prop های routing نیستند.

همانطور که می بینید به prop های routing دسترسی نداریم. حالا به سراغ روش پیشرفته ای که گفتم می رویم. ابتدا باید یک کامپوننت خاص را وارد این فایل کنید:

import { withRouter } from 'react-router-dom';

این کامپوننت یک کامپوننت HOC است و اگر export خود را درون آن قرار دهیم، در کامپوننت Burger.js نیز به prop های routing دسترسی خواهیم داشت:

export default withRouter(burger);

حالا می توانیم وارد BurgerBuilder.js شویم و درون تابع purchaseContinueHandler (پس از قسمت های کامنت شده) کدهایمان را تکمیل کنیم. در واقع اگر تمام تابع purchaseContinueHandler را به همراه قسمت های کامنت شده برایتان قرار دهم چنین چیزی خواهد بود:

    purchaseContinueHandler = () => {
        // this.setState({ loading: true })
        // const order = {
        //     ingredients: this.state.ingredients,
        //     price: this.state.totalPrice,
        //     customer: {
        //         name: 'Amir Zouerami',
        //         address: {
        //             street: 'Teststreet 1',
        //             zipCode: '9174582541',
        //             country: 'Iran'
        //         },
        //         email: 'test@test.com'
        //     },
        //     deliveryMethod: 'fastest'
        // }
        // axios.post('/orders.json', order)
        //     .then(response => {
        //         this.setState({ loading: false, purchasing: false });
        //     })
        //     .catch(error => {
        //         this.setState({ loading: false, purchasing: false });
        //     });
        this.props.history.push('/checkout');
    }

یعنی تنها دستوری که کامنت نشده است و همین الان آن را اضافه کرده ایم props.history.push است که در جلسات قبل گفتیم کاربر را به صفحه ی جدیدی منتقل می کند. حالا اگر فایل ها را ذخیره کرده و به مرورگر برویم با کلیک روی CONTINUE شاهد انتقال به صفحه ی checkout هستیم. البته در کنسول مرورگر چند خطا مربوط به event-listener ها داریم که آن ها را بعدا رفع خواهیم کرد. همچنین فعلا لینک Checkout در بالای صفحه را به این صفحه متصل نمی کنم چرا که می خواهم در جلسات بعدی آن را به My Orders (سفارشات من) تغییر دهم.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش ری اکت توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.