LoginSignup
0
1

More than 3 years have passed since last update.

react cart

Last updated at Posted at 2019-11-07

youtubeでhttps://www.youtube.com/watch?v=wPQ1-33teR4
の動画を見て学習をしたので自分のためにもまとめておきます。

react-phone-e-commerce-project/src/data.jsには

| export const storeProducts = [
|:--|
|   { |
|     id: 1, |
|     title: "Google Pixel - Black", |
|     img: "img/product-1.png", |
|     price: 10, |
|     company: "GOOGLE", |
|     info: |
|       "Lorem ipsum dolor amet offal butcher quinoa sustainable gastropub, echo park actually green juice sriracha paleo. Brooklyn sriracha semiotics, DIY coloring book mixtape craft beer sartorial hella blue bottle. Tote bag wolf authentic try-hard put a bird on it mumblecore. Unicorn lumbersexual master cleanse blog hella VHS, vaporware sartorial church-key cardigan single-origin coffee lo-fi organic asymmetrical. Taxidermy semiotics celiac stumptown scenester normcore, ethical helvetica photo booth gentrify.", |
|     inCart: false, |
|     count: 0, |
|     total: 0 |
|   }, |
|   { |
|     id: 2, |
|     title: "Samsung S7", |
|     img: "img/product-2.png", |
|     price: 16, |
|     company: "SAMSUNG", |
|     info: |
|       "Lorem ipsum dolor amet offal butcher quinoa sustainable gastropub, echo park actually green juice sriracha paleo. Brooklyn sriracha semiotics, DIY coloring book mixtape craft beer sartorial hella blue bottle. Tote bag wolf authentic try-hard put a bird on it mumblecore. Unicorn lumbersexual master cleanse blog hella VHS, vaporware sartorial church-key cardigan single-origin coffee lo-fi organic asymmetrical. Taxidermy semiotics celiac stumptown scenester normcore, ethical helvetica photo booth gentrify.", |
|     inCart: false, |
|     count: 0, |
|     total: 0 |
|   }, |

と、商品の使いたいデータをまとめておきます。

react-phone-e-commerce-project/src/context.jsには

context.js

import React, { Component } from "react";
import { storeProducts, detailProduct } from "./data";
const ProductContext = React.createContext();

class ProductProvider extends Component {
  state = {
    products: [],
    detailProduct: detailProduct,
    cart: [],
    modalOpen: false,
    modalProduct: detailProduct,
    cartSubTotal: 0,
    cartTax: 0,
    cartTotal: 0
  };

reactとsrc/data.jsからstoreProducts, detailProductをインポートする

  componentDidMount() {
    this.setProducts();
  }

  setProducts = () => {
    let products = [];
    storeProducts.forEach(item => {
      const singleItem = { ...item };
      products = [...products, singleItem];
    });
    this.setState(() => {
      return { products };
    }, this.checkCartItems);
  };

関数setProductsでproductsのなかに商品データを詰め込む

  getItem = id => {
    const product = this.state.products.find(item => item.id === id);
    return product;
  };
  handleDetail = id => {
    const product = this.getItem(id);
    this.setState(() => {
      return { detailProduct: product };
    });
  };

商品をidで管理する

  addToCart = id => {
    let tempProducts = [...this.state.products];
    const index = tempProducts.indexOf(this.getItem(id));
    const product = tempProducts[index];
    product.inCart = true;
    product.count = 1;
    const price = product.price;
    product.total = price;

    this.setState(() => {
      return {
        products: [...tempProducts],
        cart: [...this.state.cart, product],
        detailProduct: { ...product }
      };
    }, this.addTotals);
  };

やはりカートに入れるものをidで管理する

  openModal = id => {
    const product = this.getItem(id);
    this.setState(() => {
      return { modalProduct: product, modalOpen: true };
    });
  };

商品の詳細データをモーダルで表示する。やはりidで(省略

  closeModal = () => {
    this.setState(() => {
      return { modalOpen: false };
    });
  };

openModal関数と対になる関数でmodalOpenの状態をfalseに変更することでModalを閉じる処理を起こしている。

  increment = id => {
    let tempCart = [...this.state.cart];

変数tempCartにcartのstateを詰め込んでいる

    const selectedProduct = tempCart.find(item => {
      return item.id === id;
    });
    const index = tempCart.indexOf(selectedProduct);
    const product = tempCart[index];

cartのなかの商品データをidを使って特定している。
ちなみにindexOf(hogehoge)というものはindexOfメソッド。

indexOfメソッド
文字列 . indexOf ( 検索する文字列 [ , fromIndex ] )
1つ目の引数(検索する文字列)で文字列を左(先頭の文字)から右に検索して出現した位置(数値)を返します。
先頭の1文字目の位置は0です。
該当の文字がなかったときは-1を返します。
fromIndexは検索を始める位置です。省略可能です。
Stringオブジェクトのメソッドです。
以下はMDNのindexOfメソッドのリンクです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
文字列の位置を取得する
文字列の位置を取得するサンプルです。
文字列を左(先頭の文字)から検索します。

<script>

const str1 = "あいうabcあいう";

console.log(str1.indexOf("b")); // 4

console.log(str1.indexOf("abc")); // 3

console.log(str1.indexOf("あいう")); // 0

console.log(str1.indexOf("あいえ")); //-1

</script>
5,7行目は、指定した文字列が見つかった位置を返しています。
9行目は、文字列を左から見て最初に出現する"あいう"の位置を返しています。
11行目は、指定した文字がないので-1を返します。

検索開始位置を指定する
検索開始位置を指定するサンプルです。

<script>

const str1 = "あいうえお";

console.log(str1.indexOf("う",2)); // 2

console.log(str1.indexOf("う",3)); //-1

</script>
5行目の引数は2なので対象の文字列は(うえお)です。引数の文字列(う)が見つかった位置を返しています。
7行目の引数は3なので対象の文字列は(えお)です。引数の文字列(う)が見つからないので-1を返します。
    product.count = product.count + 1;
    product.total = product.count * product.price;
    this.setState(() => {
      return {
        cart: [...tempCart]
      };
    }, this.addTotals);
  };

productの中に入っているprice情報を使って値段を設定している。
stateのaddTotals(カートに入れた商品の合計の値段)状態を変更している。

  decrement = id => {
    let tempCart = [...this.state.cart];
    const selectedProduct = tempCart.find(item => {
      return item.id === id;
    });

decrement関数では変数tempCartにカーとの状態を詰め込んでいる

    const index = tempCart.indexOf(selectedProduct);
    const product = tempCart[index];
    product.count = product.count - 1;
    if (product.count === 0) {
      this.removeItem(id);
    } else {
      product.total = product.count * product.price;
      this.setState(() => {
        return { cart: [...tempCart] };
      }, this.addTotals);
    }
  };

カートの中のidで特定した商品の数が0になったらthis.removeItem(id)で商品の種類ごとカートから取り除く。
0以外の場合、商品の種類自体は残り、this.setState(() => )でaddTotalを変更している。
{でも、 0になったらなったでカートの中の合計の値段(金額)は変わるよな、、、、。}

  getTotals = () => {
    // const subTotal = this.state.cart
    //   .map(item => item.total)
    //   .reduce((acc, curr) => {
    //     acc = acc + curr;
    //     return acc;
    //   }, 0);
    let subTotal = 0;
    this.state.cart.map(item => (subTotal += item.total));
    const tempTax = subTotal * 0.1;
    const tax = parseFloat(tempTax.toFixed(2));
    const total = subTotal + tax;
    return {
      subTotal,
      tax,
      total
    };
  };

商品にかかる税の計算。parseFloatはhttps://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseFloat
参照。引数として与えられた文字列を解析して浮動小数点数を返す。
ここでやっているのはざっくり商品と税の合計金額の算出。

  addTotals = () => {
    const totals = this.getTotals();
    this.setState(
      () => {
        return {
          cartSubTotal: totals.subTotal,
          cartTax: totals.tax,
          cartTotal: totals.total
        };
      },
      () => {
        // console.log(this.state);
      }
    );
  };

this.setStateにおいて、setStateでカートのsubTotal、Tax、Totalの情報の変更をStateに伝えている。

  removeItem = id => {
    let tempProducts = [...this.state.products];
    let tempCart = [...this.state.cart];

    const index = tempProducts.indexOf(this.getItem(id));
    let removedProduct = tempProducts[index];
    removedProduct.inCart = false;
    removedProduct.count = 0;
    removedProduct.total = 0;

    tempCart = tempCart.filter(item => {
      return item.id !== id;
    });

    this.setState(() => {
      return {
        cart: [...tempCart],
        products: [...tempProducts]
      };
    }, this.addTotals);
  };

let removedProduct = tempProducts[index]; ⬅

removedProduct.inCart = false;        ⬅  

こう書くことによって商品をカートから弾いている。
商品のinCart情報をfalseにすることによってカートに存在することができなくなった。

  clearCart = () => {
    this.setState(
      () => {
        return { cart: [] };
      },
      () => {
        this.setProducts();
        this.addTotals();
      }
    );
  };

このclearCartはUIの方でカートの中の商品全消去ボタンがあるから設定している。

  render() {
    return (
      <ProductContext.Provider
        value={{
          ...this.state,
          handleDetail: this.handleDetail,
          addToCart: this.addToCart,
          openModal: this.openModal,
          closeModal: this.closeModal,
          increment: this.increment,
          decrement: this.decrement,
          removeItem: this.removeItem,
          clearCart: this.clearCart
        }}

        {this.props.children}
      </ProductContext.Provider>
    );
  }
}

const ProductConsumer = ProductContext.Consumer;

export { ProductProvider, ProductConsumer };
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1