تکمیل کد reducer برای محتویات همبرگر

Completing the Reducer Code for the Contents of the Hamburger

22 بهمن 1399
تکمیل کد reducer برای محتویات همبرگر

در قسمت قبل مقدمات کار با redux را در پروژه خود راه اندازی کردیم و یک سوال از شما پرسیدیم. به نظر شما Provider در چه قسمتی از فایل index.js قرار می گیرد؟ بیرون browser Router یا خارج از آن؟

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

جواب صحیح این است که provider عنصر پدر و دربرگیرنده بقیه باشد:

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

در مرحله بعد createStore و reducer خود را وارد فایل index.js می کنیم:

import { createStore } from 'redux';
import reducer from './store/reducer';

حالا می توانیم store خود را ایجاد کنیم:

const store = createStore(reducer);

در نهایت مثل همیشه store را به صورت prop روی provider می گذاریم:

const store = createStore(reducer);

const app = (
    <Provider store={store}>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </Provider>
);

حالا برنامه react ما از redux استفاده می کند و می توانیم با مراجعه به reducer.js کدهای آن را برای محتویات همبرگر تکمیل کنیم.

در فایل reducer.js کلیت دستور switch را می نویسیم تا type های مختلف action ها را بررسی کرده و بر اساس آن ها کاری انجام دهیم:

const reducer = (state = initialState, action) => {
    switch (action.type) {
        case actionTypes.ADD_INGREDIENT:
            return {

            };
        case actionTypes.REMOVE_INGREDIENT:
            return {

            };
        default:
            return state;
    }
};

یکی از این حالات اضافه کردن محتویات و دیگری حذف محتویات است. در جلسات قبل توضیح دادم که دستور return درون خودش نوعی break دارد بنابراین نیازی به استفاده از break درون این کدها وجود ندارد. در حال حاضر State این فایل به شکل زیر است:

const initialState = {
    ingredients: null,
    totalPrice: 4
};

در واقع محتویات را null گذاشته ایم اما این کد از burgerbuilder.js کپی شده است و در آنجا محتویات null بود چرا که آن را از سرور Firebase دریافت می کردیم:

    componentDidMount () {
        console.log(this.props);
        axios.get( 'https://react-my-burger.firebaseio.com/ingredients.json' )
            .then( response => {
                this.setState( { ingredients: response.data } );
            } )
            .catch( error => {
                this.setState( { error: true } );
            } );
    }

من در فصل بعد در رابطه با استفاده از این کد صحبت خواهم کرد اما از آنجایی که فعلا در مورد اجرای نامتقارن کدها در redux صحبت نکرده ایم، نمی توانم از این کد استفاده کنم. بنابراین مطمئن شوید که به فایل burgerbuilder.js رفته و کدهای درون componentDidMount را کامنت کنید:

    componentDidMount () {
        console.log(this.props);
        // axios.get( 'https://react-my-burger.firebaseio.com/ingredients.json' )
        //     .then( response => {
        //         this.setState( { ingredients: response.data } );
        //     } )
        //     .catch( error => {
        //         this.setState( { error: true } );
        //     } );
    }

سپس به فایل reducer.js برگشته و به صورت دستی محتویاتی را تعیین می کنیم:

const initialState = {
    ingredients: {
        salad: 0,
        bacon: 0,
        cheese: 0,
        meat: 0
    },
    totalPrice: 4
};

فعلا همه را صفر گذاشته ام تا در اول کار همبرگر هیچ محتویاتی نداشته باشد. در حال حاضر برای ADD_INGREDIENT می توان گفت که کار آسان است. باید در دستور switch مشخص کنیم کاربر روی چه محتویاتی کلیک کرده است (مثلا گوشت بوده یا پنیر؟) و سپس همان محتویات را 1 واحد افزایش دهیم. برای این کار ابتدا تمام state را کپی می کنیم. چرا؟ به دلیل اینکه در هنگام ثبت State جدید، مقادیر دست نخورده، به همان شکل قبلی باقی بمانند:

    switch (action.type) {
        case actionTypes.ADD_INGREDIENT:
            return {
                ...state
            };

در مرحله بعد شیء جدید ingredient خود را می خواهیم تا مقادیر جدید را روی آن تعیین کنیم اما یادتان باشد که کپی کردن کل state (کد بالا) باعث deep clone نمی شود و محتویات state.ingredients را دوباره باید کپی کنیم:

    switch (action.type) {
        case actionTypes.ADD_INGREDIENT:
            return {
                ...state,
                ingredients: {
                    ...state.ingredients
                }
            };

حالا برای اضافه کردن یک واحد به محتویات همبرگر از یک syntax جدید در ES6 استفاده می کنیم که به ما اجازه می دهد خصوصیات یک شیء را به صورت پویا تغییر دهیم. در این Syntax از یک جفت براکت استفاده می کنیم و نام آن خصوصیت را به صورت پویا درون این براکت قرار می دهیم. بقیه کار به صورت عادی است و باید مقدار آن خصوصیت را جلویش بنویسیم:

    switch (action.type) {
        case actionTypes.ADD_INGREDIENT:
            return {
                ...state,
                ingredients: {
                    ...state.ingredients,
                    [action.ingredientName]: state.ingredients[action.ingredientName] + 1
                }
            };

در اینجا قرار است یک خصوصیت به نام ingredientName را از action هایمان بگیریم (همانطور که می دانید می توانیم هر اطلاعاتی را که خواستیم به همراه action ارسال کنیم). این ingredientName قرار است مقدار کپی شده در شیء state.ingredients را جایگزین کند. این فرآیند برای اضافه کردن محتویات همبرگر بود اما برای حذف آن چطور؟

    switch (action.type) {
        case actionTypes.ADD_INGREDIENT:
            return {
                ...state,
                ingredients: {
                    ...state.ingredients,
                    [action.ingredientName]: state.ingredients[action.ingredientName] + 1
                }
            };
        case actionTypes.REMOVE_INGREDIENT:
            return {
                ...state,
                ingredients: {
                    ...state.ingredients,
                    [action.ingredientName]: state.ingredients[action.ingredientName] - 1
                }
            };
        default:
            return state;
    }

همانطور که انتظار می رفت اضافه کردن و حذف کردن فرآیند های کاملا مشابهی هستند با تفاوتی بسیار جزئی در انتهای هر دستور (اضافه کردن یک واحد یا کم کردن آن). بعدا در مورد اضافه کردن یا کم کردن قیمت نیز صحبت خواهیم کرد اما فعلا آن را فراموش کنید. در قسمت بعد می خواهم این reducer را به burgerBuilder متصل کنم تا بتوانیم از action ها و redux برای حذف و اضافه کردن عناصر از محتویات استفاده کنیم.

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

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