پیاده سازی سبد خرید در React Js توسط Redux

پیاده سازی سبد خرید در React Js توسط Redux

پیاده سازی سبد خرید در React Js توسط Redux

sample Cart in react js with redux

توسط : admin
در این آموزش قصد داریم نحوه پیاده سازی سبد خرید رو در سایت فروشگاهی توسط دو کتابخانه پر قدرت Redux و React Redux به شما آموزش بدهم .

 

سلام به همراهان گلم . امروز قصد دارم یکی از مباحث مهم در طراحی سایت ها ، علی الخصوص سایت هایی که قصد فروش محصول یا خدمات رو دارند و میخواهند سبد خرید رو به سایتشون اضافه کنند آموزش بدم . احتمالا در تولید و طراحی سایت در ری اکت برای پیاده سازی سبد خرید به اسم Redux برخورد کردید ؟! خوب هیچ چیز سختی نیست . از اون چیزی فکر میکنید ساده تر و جذاب تر هست .  سبد خریدی که قرار هست با هم ایجاد کنیم مثل همه سایتهای فروشگاهی به این صورت کار میکنه که با کلیک  روی افزودن به سبد از هر صفحه ای توی سایت محصول به سبد اضافه بشه و از هر جایی بتونیم به سبد دسترسی داشته باشیم و همچنین اگر تب جدیدی در مرورگر باز کردیم اطلاعات سبد در اون تب هم نمایش داده بشه . پس با من همراه باشید تا با هم یک سبد خرید ساده ولی کاملا عملیاتی و کاربردی رو پیاده کنیم . دقت داشته باشید در این آموزش تمرکزی روی استایل و زیبایی نداریم و صرفا هدف ،  پیاده سازی سبد خرید هست .

 

قدم اول برای شروع پروژه

ما در این سایت برای همه آموزش ها و طراحی ها از محیط کد نویسی Visual Studio Code استفاده میکنیم . فرض ما بر این هست که شما با نحوه استفاده از این محیط آشنا هستید و فقط نیاز دارید با پیاده سازی سبد سفارش در سایت توسط ری اکت آشنا بشید .

پس ابتدایک پروزه React رو ایجاد میکنیم . توسط چی ؟ معلومه دستور معروف 

npx create-react-app samplecart

 

 

اگر که هنوز create-react-app رو نصب نکردید ابتدا این دستور رو اجرا کنید

npm i -g create-react-app

 

 

اون اسم samplecart چی هست ؟ اسم پروژه ما هست که باید بعد از فرمان create-react-app نوشته بشه و نباید همنام با ماژولهای مورد استفاده در پروژه  باشه . بعد از اجرای این دستور فولدری با همین نام در مسیر مشخص شده ایجاد میشه . اکی ؟

 

پس ادامه میدیم

بعد از اجرای دستور ساخت پروژه ری اکت یک مقدار صبر میکنیم تا همه ماژول های مورد نیاز نصب بشن . سپس فولدری رو که با نام پروژه یعنی samplecart ساختیم رو از منو File/Open Folder انتخاب میکنیم

خوب الان نیاز داریم که ماژول های مورد استفاده در پروژه رو نصب کنیم . نحوه استفاده ماژول ها رو در طول آموزش بهتون توضییح میدم . ماژولی مثل بوت استرپ رو فقط برای استایل دهی استفاده میکنیم و چون به موضوع آموزش مرتبط نمیشه میتونید در فایل کدها نحوه استفاده از اون رو ببینید .

درون ترمینال که توسط کلید میانبر Ctrl + `   (کنترل + بک تیک ) فعال میشه ، دستور زیر رو اجرا کنید

npm i redux react-redux bootstrap

 

 

Redux و React Redux چی هستن ؟

به زبون ساده وقتی قصد دارید توی پروژه ری اکت مقادیری رو بین کامپوننت ها رد و بدل کنید ، اگر در حد یکی دو کامپوننت داشته باشید که هیچ ولی وقتی تعداد اونها زیاد شد و کامپوننت ها  تو در تو شدن ، اونوقته که نیاز دارید از این دو ماژول استفاده کنید . استفاده زیادی میشه از اونها کرد . به طور مثال اطلاعاتی رو که در طول اجرای برنامه نیاز دارید که از سرور گرفته بشه و ثابت هست مثل اطلاعات کاربر پس از لاگین ، خوب میتونید این اطلاعات رو در مخزنی که توسط ریداکس ایجاد میشه ذخیره و در هر جای سایت که خواستید به راحتی فراخوانی کنید . اینطوری دیگه نیاز ندارید برای بدست آوردن برخی اطلاعات مدام درخواست رو به سمت سرور ارسال کنید یکبار دریافت و ذخیره میکنید و هر بار دوست داشتید از مخزن دریافت میکنید .یادتون باشه به مقادیر ارسالی در ری اکت props گفته میشه و در واقع شما دارید props رو رد و بدل میکنید .حالا کار هر کدوم چی هست ؟ redux وظیفه ایجاد مخزن و مدیریت اون رو داره و react redux همونطور که از اسمش مشخصه وظیفه اتصال redux به react  رو داره تا با ایجاد این اتصال شما بتونید هر مقداری رو از هر کامپوننتی به هر کامپوننت دیگه ای ارسال کنید .

 

ادامه کار :

برخی فایلها رو که پیش فرض ری اکت ایجاد میکنه پاک کردم ، اگر فایلی رو در پروژه ندیدید نگران نشید . مثل App.css ,App.test.js , Setup.test.js .

حالا در فولدر ریشه یعنی src  تعداد 5  فولدر برای جدا سازی و کنترل بهتر پروژه ایجاد میکنیم

 


 

در فولدر Data فایل جدیدی با نامه data.js اضافه و اطلاعات زیر رو درونش کپی کنید . این قرار هست اطلاعات محصولات ما باشه .

 

const products = [
  {
    _id: 1,
    productName: "موبایل",
    price: 12000000
  },
  {
    _id: 2,
    productName: "تبلت",
    price: 24000000
  },
  {
    _id: 3,
    productName: "مانیتور",
    price: 18000000
  },
  {
    _id: 4,
    productName: "لپ تاپ",
    price: 42000000
  },
  {
    _id: 5,
    productName: "سی پی یو",
    price: 32000000
  },
  {
    _id: 6,
    productName: "موس",
    price: 190000
  },
  {
    _id: 7,
    productName: "کیبورد",
    price: 10000000
  },
  {
    _id: 8,
    productName: "وب کم",
    price: 16000000
  }
];

 
export function getProducts() {
  return products;
}

 

 

در فولدر Actions فایلی با نام index.js اضافه میکنیم . این فایل در واقع دستوراتی هست که قراره به مخزن داده در ریداکس ارسال کنیم که به این دستورات action میگن . کار اکشن اعمال تغییر در مخزن هست و فقط اکشن ها  از طریق reducer ها اجازه ایجاد تغییر در اطلاعات مخزن رو دارن . متدهای موجود جهت افزودن به سبد ، افزایش و کاهش تعداد و حذف یک کالا از سبد هستند.

 

export const addTocart = product => ({
  type: "ADD_TO_CART",
  product
});

 
export const incrementCart = _id => ({
  type: "INCREMENT_CART",
  _id
});

 
export const decrementCart = _id => ({
  type: "DECREMENT_CART",
  _id
});

 
export const removeFromCart = _id => ({
  type: "REMOVE_CART",
  _id
});

 

 

در فولدر Store یک فایل به نام localStorage.js اضافه میکنیم و اطلاعات زیر رو توی این فایل کپی میکنیم. وظیفه این قسمت ذخیره اطلاعات و همچنین گرفتن اطلاعات ذخیره شده در local storage یا حافظه مرورگر سیستم کاربر هست . این حافظه به راحتی با دستورات localStorage.get و localStorage.set قابل دسترسی هست . برای این از حافظه مرورگر استفاده میکنیم  اینه که بتونیم اطلاعات سبد رو در هر تب جدیدی هم  به نمایش بگذاریم . یاتون باشه برای ذخیره اطلاعات باید آرایه ها رو به صورت رشته ای از فرمت json تبدیل و سپس ذخیره کنیم و در زمان بازیابی مجددا اطلاعات رشته ذخیره شده رو مجددا به آرایه تبدیل کنیم .

export const loadState = key => {
  try {
    const serializedState = localStorage.getItem(key);
    if (serializedState === null) {
      return [];
    }

 
    const result = JSON.parse(serializedState);
    return result;
  } catch (err) {
    return [];
  }
};

 
export const saveState = (key, value) => {
  try {
    const result = JSON.stringify(value);
    localStorage.setItem(key, result);
  } catch (err) {}
};

 

 

خوب الان نیاز به Reducer داریم . کار Reducer ها اعمال دستورات اکشن در مخزن هست . به اینصورت که دستورات اول به action ارسال میشه و reducer این دستورات رو از action گرفته و روی مخزن اعمال میکنه . پس یک فایل درون فولدر Reducers به نام defaultReducer.js با محتویات زیر ایجاد میکنیم . 

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

در ادامه یک فرمت استاندارد reducer ایجاد کردیم و مقادیر پیش فرض مخزن و مقدار اکشن رو به عنوان پارامتر بهش پاس دادیم . بقیه کدها هم که مشخص هستند . مقدار type خصوصت هر اکشن بررسی و بر اساس اون تصمیم میگیریم که چه عملی رو داده های مخزن انجام بشه . 

import { loadState } from "./../Store/localStorage";
const persistedState = loadState("shoppingCart");

 
const defaultState = {
  shoppingCart: persistedState
};

 
export default (state = defaultState, action) => {
  const cartItems = [...state.shoppingCart];
  switch (action.type) {
    case "ADD_TO_CART":
      if (cartItems.filter(a => a._id === action.product._id).length > 0) {
        cartItems.map(a => {
          if (a._id === action.product._id) {
            a.count++;
          }
          return a;
        });
      } else {
        const newModel = {
          _id: action.product._id,
          productName: action.product.productName,
          price: action.product.price,
          count: 1
        };
        cartItems.push(newModel);
      }
      return Object.assign({}, state, {
        shoppingCart: cartItems
      });

 
    case "REMOVE_CART":
      const filterList = cartItems.filter(a => a._id !== action._id);
      return Object.assign({}, state, {
        shoppingCart: filterList
      });

 
    case "DECREMENT_CART":
      cartItems.map(a => {
        if (a._id === action._id) {
          if (a.count > 1) {
            a.count--;
          }
        }
        return a;
      });

 
      return Object.assign({}, state, {
        shoppingCart: cartItems
      });

 
    case "INCREMENT_CART":
      cartItems.map(a => {
        if (a._id === action._id) {
          a.count++;
        }
        return a;
      });

 
      return Object.assign({}, state, {
        shoppingCart: cartItems
      });

 
    default:
      return state;
  }
};

 

 

 

تقریبا دیگه کار داره تمام میشه حالا وقتشه که مخزن رو توسط Redux ایجاد و در فایل اجرایی برنامه فراخوانی کنیم . پس یک فایل دیگه به نام configureStore.js رو در فولدر Store با محتویات زیر ایجاد میکنیم . در خط اول  ، دستور ایجاد مخزن رو از ریداکس میگیریم . در خط دوم reducer رو که ساختیم فراخوانی میکنیم . در نهایت تابعی ایجاد میکنیم که درون این تابع با گرفتن مقدار reducer پیش فرض به عنوان پارامتر در متد ایجاد store اضافه کرده و تابع رو در اولین فایل اجرایی سایت یعنی Index.js فراخوانی میکنیم . بریم سراغ فایل index.js .

import { createStore } from "redux";
import defaultReducer from "../Reducers/defualtReducer";

 
export function configureDefaultSetting() {
  const store = createStore(defaultReducer);
  return store;
}

 

 

 

فایل Index.js باید شبیه این باشه . در این قسمت Provider رو از react redux اضافه میکنیم و کامپوننت App رو درون این کامپوننت والد قرار میدیم و هدف از اینکار اینه که مخزن در کل پروژه قابل دسترس باشه و از طریق متد connect در هر کامپوننتی که خواستیم به مقادیر موجود در مخزن دسترسی پیدا میکنیم .

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import "bootstrap/dist/css/bootstrap.min.css";
import { configureDefaultSetting } from "./Store/configureStore";
import { saveState } from "./Store/localStorage";
import { Provider } from "react-redux";

 
const store = configureDefaultSetting();

 
store.subscribe(() =>
  saveState("shoppingCart", store.getState()["shoppingCart"])
);

 
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

 
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

 

 

کدهای کامپوننت سبد (Cart.jsx) که در فولدر Components ایجاد میکنیم به صورت زیر هست . در انتهای کدها متد connect قرار داره که به راحتی اتصال به مخزن رو فراهم میکنه و میتونید هم به داده های درون اون دسترسی داشته باشید و هم دستورات اکشن رو به مخزن ارسال کنید . دوستان دقت کنید برای دسترسی به این مقادیر باید به props مراجعه کنید . به این صورت  this.props.shoppingCart و یا برای ارسال دستورات اکشن به این شکل عمل میکنیم this.props.dispatch که درون متد اعزام (dispatch) متد های موجود در فایل index.js در فولدر actions رو به عنوان پارامتر ارسال میشود .

import React, { Component } from "react";
import { connect } from "react-redux";
import {
  decrementCart,
  removeFromCart,
  incrementCart
} from "./../Actions/index";

 
class Cart extends Component {
  state = {};
  render() {
    const { shoppingCart } = this.props;
    return (
      <div className="p-1 border">
        <h2>سبد خرید</h2>
        <div className="row m-0">
          {shoppingCart.map((product, index) => {
            return (
              <div className="col-md-12" key={index}>
                <div className="row m-0">
                  <div className="col-md-3">{`نام محصول ${product.productName}`}</div>
                  <div className="col-md-3">{`قیمت ${product.price}`}</div>
                  <div className="col-md-3">{`تعداد ${product.count}`}</div>
                  <div className="col-md-3">
                    <button
                      onClick={() => {
                        this.props.dispatch(incrementCart(product._id));
                      }}
                      className="btn btn-sm btn-success"
                    >
                      افزایش
                    </button>
                    <button
                      className="btn btn-sm btn-info"
                      onClick={() => {
                        this.props.dispatch(decrementCart(product._id));
                      }}
                    >
                      کاهش
                    </button>
                    <button
                      className="btn btn-sm btn-danger"
                      onClick={() => {
                        this.props.dispatch(removeFromCart(product._id));
                      }}
                    >
                      حذف
                    </button>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    );
  }
}

 
export default connect(state => {
  return {
    shoppingCart: state.shoppingCart
  };
})(Cart);

 

 

فایل Products.jsx هم به فولدر Components  با محتویات  زیر اضافه میکنیم . اگر دقت کنید در این کامپوننت در متد connect  مقداری رو از مخزن دریافت نکردیم ولی برای اینکه بتونیم دستوری رو اعزام کنیم باید حتما اتصال برقرار بشه . در این کامپوننت دستور اضافه شدن به سبد قرار میگیره .

import React, { Component } from "react";
import { getProducts } from "./../Data/data";
import { connect } from "react-redux";
import { addTocart } from "./../Actions/index";

 
class Products extends Component {
  state = {
    products: []
  };
  componentDidMount() {
    const products = getProducts();
    this.setState({
      products
    });
  }

 
  render() {
    return (
      <div className="p-2" style={{ direction: "rtl", textAlign: "right" }}>
        <h2>محصولات</h2>
        <div className="row m-0 border p-2">
          {this.state.products.map((product, index) => {
            return (
              <div className="col-md-3 p-1" key={index}>
                <div className="border border-success p-2">
                  <h5>{`نام محصول : ${product.productName}`}</h5>
                  <h5>{`قیمت : ${product.price}`}</h5>
                  <button
                    onClick={() => {
                      this.props.dispatch(addTocart(product));
                    }}
                    className="btn btn-success"
                  >
                    افزودن به سبد خرید
                  </button>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    );
  }
}

 
export default connect()(Products);

 

 

فایل App.js هم به این صورت تغییر پیدا میکنه . در این فایل ما تعداد محصولات رو در منو قرار هست که نمایش بدیم 

import React from "react";
import Products from "./Components/Products";
import Cart from "./Components/Cart";
import { connect } from "react-redux";

 
const App = ({ shoppingCart }) => {
  return (
    <div className="App p-1" style={{ direction: "rtl", textAlign: "right" }}>
      <div className="bg-dark text-white p-2">
        تعداد در سبد خرید{" "}
        <span className="badge badge-success">{shoppingCart.length}</span>
      </div>
      <div className="row m-0">
        <div className="col-md-12">
          <Products />
        </div>
        <div className="col-md-12">
          <Cart />
        </div>
      </div>
    </div>
  );
};

 
export default connect(state => {
  return {
    shoppingCart: state.shoppingCart
  };
})(App);

 

 

و آخرین مورد ، اگر فایل فشرده پروژه رو از اینجا دانلود کردید یادتون باشه باید دستور npm i رو اجرا کنید تا ماژولهای استفاده شده نصب بشن تا پروژه قابل اجرا باشه . رمز فایل فشرده nilootech.com هست .

بسیار خوب . دیگه تمام شد الان میتونید خروجی با دستور npm start ببینید . امیدوارم این آموزش به شما کمک کنه تا براحتی سبد خریدتون در برنامه پیاده کنید . اگر نظر یا سوالی دارید خوشحال میشم  زیر هم آموزش با من در میون بگذارید .

خروجی نهایی سبد سفارش در ری اکت

 

 

 

 

نظرات :

در عرض چند دقیقه برای ایجاد حساب

کاربری خود اقدام کنید


اکنون حساب کاربری خود را ایجاد کنید!


ایجاد حساب کاربری

با ثبت نام در نیلوتک از آخرین بروز رسانی های آموزش ها و مقالات سایت مطلع شوید