비회원 장바구니 만들기

박경찬·2022년 9월 22일
0

이전 포스팅에 cookies,SessionStorage,LocalStorage 를 봤다

이번에는 LocalStorage 를 활용해서 비회원장바구니 를 만들어보자!

진행 형식은!☝🏼

기존 데이터를 불러와 map 으로 뿌려주고 장바구니 버튼을 만들어 브라우저에 저장하려고 한다.

주의 해야할점은 button 태그에 id 속성값을 사용하지 않는다 이유는 HTML은 텍스트 형식이기 때문에 객체가 들어갈수가 없다.

 <button id={}>장바구니담기</button>

하지만 방법은 있다.

<button id={JSON.stringfy()}></button>

JSON.stringfy()를 사용해 텍스트로 변경해서 사용하면된다.

하지만 여기서 하고자 하는건 HOF( Higher-order function )을 이용해 함수에게 직접 데이터를 통째로 전달하고자 한다.

 const saveBasket = (item: any) => () => {
    localStorage.setItem("basket", item);
    
  };
<button onClick={saveBasket(item)}>장바구니담기</button>

실제로 확인해보면 local Storage[object Object]형식으로 저장된다.

이유는 아까 처럼 텍스트만 들어갈수 있는데 객체의 형식으로 들어가게 되면 object 형식을 볼수 있다.

자 그러면 객체를 텍스트로 바꿔 넣어줘야한다.

  const saveBasket = (item: any) => () => {
    localStorage.setItem("basket", JSON.stringify(item));
  };

필자는 필요한 부분만 가져오기 위해 rest파라미터를 사용했다.

 const { __typename, ...NewItem } = item;
localStorage.setItem("basket", JSON.stringify(NewItem));

자 여기까지는 이제 브라우저에 원하는 데이터를 담을수 있게되었다.
하지만 지금은 장바구니를 담을때 마다 새로고침이 되고 있는데 추가하는 형식으로 하기 위해서는 이전에 저장되었던 데이터를 가져와서 NewItem 과 합쳐야 한다.

 const basket = JSON.parse(localStorage.getItem("basket") || "[]");

JSON.parse 로 객체 또는 배열로 만들어 선언한 변수에 값을 할당해주면된다.

오호 잘들어간다~✌🏻

이제 이전데이터 까지 모두 들어간다. 하지만 중복데이터 까지 들어가기 때문에 필터작업을 해줘야한다.

    const basketTemp = basket.filter(
      (basketItem: any) => basketItem._id === item._id
    );
    if (basketTemp.length === 1) {
      alert("이미 장바구니에 담긴 상품입니다.");
      return;
    }

이미 담겨있는 아이템의 아이디와 마우스로 클릭하는 아이템의 id가 가 있는지 확인해주면 된다. 있다면 return 으로 함수를 종료 해주면 끝!✌🏻

전체코드

import { gql, useQuery } from "@apollo/client";
import styled from "@emotion/styled";
import { IUseditem } from "../../src/commons/types/generated/types";

export const FETCH_USED_ITEMS = gql`
  query fetchUseditems($page: Int) {
    fetchUseditems(page: $page) {
      _id
      name
      contents
      pricea
      tags
      images
      useditemAddress {
        address
        createdAt
      }
      createdAt
    }
  }
`;

const MyRow = styled.div`
  display: flex;
`;

const MyColumn = styled.div`
  width: 25%;
`;

export default function BasketPage() {
  const { data } = useQuery(FETCH_USED_ITEMS);

  const saveBasket = (item: IUseditem) => () => {
    const basket = JSON.parse(localStorage.getItem("basket") || "[]");
    const basketTemp = basket.filter(
      (basketItem: IUseditem) => basketItem._id === item._id
    );
    if (basketTemp.length === 1) {
      alert("이미 장바구니에 담긴 상품입니다.");
      return;
    }
    const { __typename, ...newItem } = item;
    basket.push(newItem);

    localStorage.setItem("basket", JSON.stringify(basket));
  };

  return (
    <div>
      {data?.fetchUseditems.map((item: IUseditem) => (
        <MyRow key={item._id}>
          <MyColumn>{item.name}</MyColumn>
          <MyColumn>{item.price}</MyColumn>
          <button onClick={saveBasket(item)}>장바구니담기</button>
        </MyRow>
      ))}
    </div>
  );
}

이제 담겼으니 장바구니에 담긴 아이템을 봐야하지 않을까?

useEffect(() => {
    
    const baskets = JSON.parse(localStorage.getItem("baskets") || "[]");
    setBesketItem(baskets);
  },[]);

useEffect를 사용해서 로컬스토리지를 찾아준다!

그리고 스테이트가 변경되면서 리렌더가 될거고 브라우저에 그려주게 된다.

useEffect 말고도 typeof window를 사용해서 윈도우가 있는지 없는지로도 확인가능하다

if ( typeof window !== "undifined"){
  const baskets = JSON.parse(localStorage.getItem("baskets") || "[]");
  setBesketItem(baskets);
}

전체코드


import styled from "@emotion/styled";
import { useEffect, useState } from "react";
import { IUseditem } from "../../src/commons/types/generated/types";

const MyRow = styled.div`
  display: flex;
`;

const MyColumn = styled.div`
  width: 25%;
`;

export default function BasketPage() {
  const [basketItem, setBesketItem] = useState([]);

  // if ( typeof window !== "undifined"){
  //   const baskets = JSON.parse(localStorage.getItem("baskets") || "[]");
  //   setBesketItem(baskets);
  // }

  useEffect(() => {
    // 로컬스토리지를 찾기 위해 유즈 이펙트를 사용한다
    const baskets = JSON.parse(localStorage.getItem("basket") || "[]");
    setBesketItem(baskets);
  },[]);

  return (
    <div>
      {basketItem.map((el: IUseditem) => (
        <MyRow key={el._id}>
          <MyColumn>{el.name}</MyColumn>
          <MyColumn>{el.price}</MyColumn>
        </MyRow>
      ))}
    </div>
  );
}

0개의 댓글