쇼핑몰 장바구니를 만들어 봅시다.

박상준·2023년 12월 15일

장바구니 구현하기

상품을 보여주기만 한다면 아무런 의미없는 페이지이다. 구매할 상품을 담는 기능을 해야지만 쇼핑몰이라고 할수 있다. 그래서 장바구니를 구현하기 앞서 간단한 조건을 만들어 주겠다.

  1. 같은 물건이 담기지 않도록 방지
  2. 3개 이상의 물건이 담기지 않도록 방지
  3. 새로고침해도 장바구니 정보 유지하기

장바구니 정보 저장하기

정보를 저장하는 방법은 간단하다. 물론 가장 좋은 방법은 데이터베이스를 구현해 서버에 저장하는 방법이 가장 좋지만 현재 단계에서는 간단하게 구현하겠다. 투두리스트에서 사용했던 방법인 localstorage를 활용하겠다.

function Merchandise ({ item }){
    const [bag, setBag] = useState([]);

우선은 bag이라는 배열을 만들어 장바구니에 추가한 item을 담아준다.

    const calculator = (e) => {
        for(let i = 0; i < bag.length; i++){
             if(bag[i].item_no === e.item_no){
                return e.item_no;
            };
        };
    };

그리고 가장 먼저 진행할 중복검사 함수를 만들어준다. 중복검사는 for문을 사용해 배열을 순회하면서 선택한 item과 배열안에 있는 item의 item_no를 비교한다. 만약 같은 결과가 나오면 item_no를 return한다.

    const increaseBag = (item) => {
        const addItem = {...item}
        const result = calculator(addItem)
        if(result === addItem.item_no){
            alert('이미 같은 상품이 장바구니에 담겨있습니다!');

그리고 장바구니에 추가하는 함수를 만들어 준다. 우선 item데이터를 직접 사용하지 않고 spread를 통해 지역변수를 만들어 활용해주기로 했다. 그래서 가장 먼저 addItem이라는 지역 변수를 만들고 위에서 만든 calculator함수에 넣어 그 결과값을 result변수에 넣어준다.
그리고 배열에 추가하기 전에 중복검사를 먼저 진행한다. 만약 result값과 item의 값이 같다면 alert을 보여주고 if문을 끝낸다.

만약 다른 값이라면 바로 데이터를 배열에 추가한다. 리액트에서는 원본 데이터의 불변성을 위해 데이터를 복사한 값을 사용해줘야하는 사실을 알고 있다.

        else if(bag.length < 3){
            const bagList = [...bag,addItem];
            setBag(bagList);
            localStorage.setItem('bags',JSON.stringify(bagList));
            alert('장바구니에 상품이 담겼습니다!');
        }else{
            alert('장바구니에는 최대 3개의 물건만 남을수 있습니다!');
        };
    };

그래서 bagList라는 변수에 기존 배열인 bag의 데이터를 spread연산자를 통해 복사하고 item값인 addItem을 추가해준다. 그리고 변경된 데이터를 state값으로 바꿔준 후 localstorage에 bags라는 이름으로 배열을 저장해 준다.

만약 배열의 길이가 3을 넘어간다면 alert을 보여주고 배열에 추가하지 않는다.

장바구니 페이지 만들기

장바구니에 담긴 배열을 페이지에 보여주는 코드를 작성해보겠다. 상품을 렌더링하는 방법과 동일하게 만들어준다

     return(
        <>
        {bag && (
            <div className="cart">
            {bag.map((item)=>(
                <BagList 
                item={item}
                key={item.item_no}/>
            ))}
            </div>
        )}
        </>
    );

우선 장바구니의 배열을 localstorage에서 받아 state값을 지정해준다. 그리고 장바구니의 데이터가 있을 경우에 배열을 렌더링해준다. 상품 페이지와 동일하게 key값으로 item_no을 지정한다.

그러면 장바구니에 있는 상품만 렌더링이 가능하다. 이제 장바구니에 가격 정보, 수량, 삭제 기능을 추가해보겠다.

상품 수량

상품수량은 간단하게 구현했다. 수량이 올라가는 버튼과 내려가는 버튼을 만들어주고 최소 수량 1개 이상이 되도록 해준다.
우선 장바구니의 배열에 수량 정보를 추가해준다.

        else if(bag.length < 3){
            const bagList = [...bag,addItem];
            setBag(bagList);
            addItem.count = 1;
            localStorage.setItem('bags',JSON.stringify(bagList));
            alert('장바구니에 상품이 담겼습니다!');
        }else{
            alert('장바구니에는 최대 3개의 물건만 남을수 있습니다!');
        };
    };

장바구니에 담는 시점에서 addItem.count라는 속성을 추가하여 기본 수량을 1로 지정해준다. 그리고 장바구니에서 count값을 보여주면 된다. count값을 해당 컴포넌트에서 state값으로 지정해준다.

    const[piece,setPiece] = useState(item.count);

그리고 up,down 버튼도 만들어 주도록 하겠다.

   <button onClick={up}>+</button>
   <button onClick={down}>-</button>

그리고 버튼을 눌렀을때 실행되는 함수를 작성해준다.

    const up = () => {
        const increasePiece = piece + 1;
        setPiece(increasePiece);
    };

up함수는 간단하다. increasePiece라는 변수에 1을 추가해주고 그 값을 state값으로 저장해준다.

    const down = () => {
        if(piece === 1){
            alert('최소 수량은 1개입니다.')
            return;
        };
        const decreasePiece = piece - 1;
        setPiece(decreasePiece);
    };

down함수는 최소 수량을 1로 제한하는 조건문을 넣어준다. 만약 down버튼을 눌렀을때 수량이 1이라면 alert을 보여주고 수량을 바꾸지 않는다. 1개 이상일때에만 수량이 줄어든다.
이제 추가한 버튼과 수량을 장바구니 아이템 코드에 추가해준다.

    <div className="bagBtn">
     수량 : {piece}
     <button onClick={up} disabled={disabled}>+</button>
     <button onClick={down} disabled={disabled}>-</button>
    </div>

확인해보면 정상적으로 수량이 늘어나고 1개 이하일때는 alert을 보여준다.

마무리

이제 장바구니까지 대략 만들어졌다. 하지만 장바구니라면 가격정보와 상품 선택하는 체크박스가 있어야 하고 내가 원하는 상품을 결제할 수 있다. 한 포스트에 다 담을 계획이었지만 너무 길어지는것 같아 다음 포스트로 넘겨주겠다. 간단하게 계획을 말하자면 체크박스는 컴포넌트로 만들어 관리해줄 것이고 체크된 상품만 가격을 계산해 숫자를 표시해주도록 할 것이다. 체크했을때에는 수량을 변경하지 못하도록 방지하는 기능을 넣어보도록 하겠다.

profile
개인 블로그 플렛폼도 운영중입니다(https://blog-park.vercel.app/)

0개의 댓글