حالا که با مفاهیم پیشرفته redux آشنا شده ایم وقت اضافه کردن آن به پروژه همبرگرساز رسیده است. برای اضافه کردن redux به این پروژه بهتر است ابتدا redux devtools را داشته باشیم تا بتوانیم به شکل بهینه تری با این کتابخانه کار کنیم و مشکلات برنامه را به دست بیاوریم. به همین خاطر ابتدا به صفحه گیت هاب redux devtools بروید. فعلا در پروژه همبرگرساز هیچ middleware ای استفاده نکرده ایم بنابراین نیازی به استفاده از قسمت advanced نداریم بلکه از نحوه راه اندازی basic استفاده می کنیم. البته بعدا middleware ها را به کد خود اضافه کرده و از آن ها نیز استفاده می کنیم اما فعلا بدون middleware شروع می کنیم. طبق اطلاعات صفحه گیت هاب نحوه راه اندازی basic به شکل زیر است:
const store = createStore( reducer, /* preloadedState, */ + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() );
یعنی تنها کاری که باید انجام دهیم اضافه کردن متغیر عجیب و غریب بالا به CreateStore است، بنابراین به فایل index.js از پروژه همبرگرساز بروید و این مورد را به دستور createStore بدهید:
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
با انجام این کار به مرورگر رفته و به سربرگ redux بروید. ابزار redux devtools باید به درستی برای شما کار کرده و با تغییر محتویات، شاهد تغییر state در این ابزار باشید.
برای شروع با نحوه سفارش همبرگرها شروع می کنم. در حال حاضر منطق ثبت سفارش را در فایل ContactData.js داریم:
orderHandler = (event) => { event.preventDefault(); this.setState({ loading: true }); const formData = {}; for (let formElementIdentifier in this.state.orderForm) { formData[formElementIdentifier] = this.state.orderForm[formElementIdentifier].value; } const order = { ingredients: this.props.ings, price: this.props.price, orderData: formData } axios.post('/orders.json', order) .then(response => { this.setState({ loading: false }); this.props.history.push('/'); }) .catch(error => { this.setState({ loading: false }); }); }
زمانی که فرم ثبت می شود ما State را روی حالت loading می گذاریم تا spinner نمایش داده شود و پس از پایان فرآیند ثبت سفارش در پایگاه داده، کاربر را به صفحه اصلی redirect می کنیم. ما می توانیم این کار ها را به عهده action creator ها و کتابخانه redux بگذاریم. برای انجام این کار ابتدا باید ساختار پوشه ها را کمی دست کاری کنیم.
درون پوشه store دو پوشه دیگر به نام های actions و reducers ایجاد کنید. سپس فایل actions.js را به درون پوشه actions و reducer.js را به درون reducers انتقال دهید. حالا فایل actions.js را به actionTypes.js و reducer.js را به burgerBuilder.js تغییر نام دهید تا ظاهر کار مثل پروژه شمارنده باشد. در مرحله بعد وارد پوشه actions (درون Store) شده و فایل جدیدی به نام orders.js را ایجاد کنید. این فایل قرار است حاوی action creator هایی باشد که وظیفه ثبت سفارش را بر عهده دارند. سپس وارد پوشه reducers شده و نام آن را دوباره order.js بگذارید. در نهایت باید دوباره وارد پوشه actions شده و یک فایل دیگر به نام burgerBuilder.js بسازیم تا action creator های مربوط به ساخت همبرگر (انتخاب محتویات) را در آن قرار دهیم.
در حال حاضر برنامه ما به هم ریخته است بنابراین هیچ قسمتی از آن کار نخواهد کرد اما مشکلی نیست، بعدا آن را مرتب می کنیم. فعلا وارد پوشه actions و سپس فایل burgerBuilder بشوید تا برخی از actionCreator ها را تعریف کنیم. اولین کار وارد کردن actionTypes است:
import * as actionTypes from './actionTypes';
حالا اولین action creator خود را می سازیم:
export const addIngredient = ( name ) => { return { type: actionTypes.ADD_INGREDIENT, ingredientName: name }; };
آیا می دانید چرا name را به آن پاس داده ام؟ اگر یادتان باشد در فایل BurgerBuilder.js منطق dispatch کردن این action را پیاده سازی کرده بودیم:
const mapDispatchToProps = dispatch => { return { onIngredientAdded: (ingName) => dispatch({type: actionTypes.ADD_INGREDIENT, ingredientName: ingName}), onIngredientRemoved: (ingName) => dispatch({type: actionTypes.REMOVE_INGREDIENT, ingredientName: ingName}) } }
همانطور که می بینید نام محتویات همبرگر را در این قسمت با Action ارسال می کنیم (ingName) بنابراین ما هم باید در ActionCreator این مقدار را داشته باشیم تا کدهایمان دچار مشکل نشوند. actionCreator بعدی ما نیز برای حذف کردن محتویات است که می توانیم به شکل زیر آن را کدنویسی کنیم:
export const removeIngredient = ( name ) => { return { type: actionTypes.REMOVE_INGREDIENT, ingredientName: name }; };
بنابراین ظاهر آن بسیار شبیه به addIngredient است. در مرحله بعد وارد پوشه reducers شده و burgerBuilder.js را باز کنید تا دستور import آن را تصحیح کنیم چرا که پس از تغییر ساختار پوشه ها دستور import آن دیگر صحیح نیست. دستور صحیح به شکل زیر است:
import * as actionTypes from '../actions/actionTypes';
همین کار را برای index.js نیز انجام می دهیم. وارد index.js شده و دستور زیر را:
import reducer from './store/reducer';
به این دستور تغییر دهید:
import burgerBuilderReducer from './store/reducers/burgerBuilder';
قاعدتا حالا باید به جای reducer، مقدار burgerBuilder را به createStore پاس بدهیم:
const store = createStore(burgerBuilderReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
همچنین وارد پوشه store و سپس actions شده و فایلی جدید به نام index.js ایجاد کنید. این فایل همان فایل واحدی است که قرار است همه actioncreator های ما را یکجا جمع کند. دقیقا مثل پروژه شمارنده در این فایل index.js نیز می گوییم:
export { addIngredient, removeIngredient } from './burgerBuilder'; export { } from './order';
در مرحله بعد وارد پوشه container و سپس BurgerBuilder شده و فایل BurgerBuilder.js را باز کنید تا از actionCreator خود استفاده کنیم. اولین کار تغییر دستور زیر:
import * as actionTypes from '../../store/actions';
به دستور زیر است:
import * as burgerBuilderActions from '../../store/actions/index';
سپس به راحتی به جای dispatch کردن شیء Action به صورت مستقیم، از actionCreator های خود استفاده می کنیم:
const mapDispatchToProps = dispatch => { return { onIngredientAdded: (ingName) => dispatch(burgerBuilderActions.addIngredient(ingName)), onIngredientRemoved: (ingName) => dispatch(burgerBuilderActions.removeIngredient(ingName)) } }
فایل ها را ذخیره کنید و به مرورگر برگردید. درون مرورگر باید بتوانید با کلیک روی گزینه های More و Less محتویات همبرگر را بدون خطا تغییر دهید. اگر نمی توانید محتویات همبرگر را تغییر دهید، کدها را دوباره چک کنید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.