감자튀김 공장🍟

[React] 장바구니 수량 변경 문제2 본문

Study/React

[React] 장바구니 수량 변경 문제2

Potato potage 2021. 3. 2. 01:07
반응형

저번의 문제는 Quantity 값을 변경하면 console 값에는 반영이 되어서 출력이 되는데 화면이 리렌더링 되지 않는 점이였다. 몇 번의 시행착오를 겪으면서 생긴 문제점들을 나열해보자면

 

 

  1. 화면에 바뀐 값이 리렌더링이 안돼서 useState로 값을 관리할려고 추가했더니 렌더링 무한루프에 빠졌다.
  2. 최종 금액 값이 리렌더링이되면 장바구니 배열의 수량도 같이 렌더링이 되어야하는데 둘 중에 하나만 리렌더링 된다.
  3. id: 3의 quantity를 3에서 5로 변경하고 id: 10의 quantity를 변경하면 id 마다 quantity가 변경되는 것이 아니라 한 값에서 변경이 이루어졌다. 즉, id: 10의 quantity가 뭐였던 id: 3의 마지막 값인 5에서 변경이 이루어졌다.
  4. 수량 조절 버튼(+/-)을 두 번 누르면 TypeError: Cannot read property 'Id' of undefined 오류가 떴다.
  5. 객체 배열 Quantity 값이 변경되는 것이 아니라 배열에 Quantity가 새로 추가된다.

 

줄여보자면 이정도의 오류가 있었고, 원래는 더 대환장스러운 오류들도 있었다. 증감 버튼을 누르면 갑자기 화면에서 출력되어있던 내용들이 다 사라진다던가...

 

 

원래는 Cart.js에서 FinalCart.js로 장바구니 리스트를 넘겨주고 FianlCart.js에서 넘겨받은 리스트로 json 객체를 만들어서 화면에 리렌더링하고 그랬었는데, 굳이 그렇게 할 필요가 있나? 느꼈었다. useState로 변경되는 값들을 제어하기 위해서 애초에 Cart.js에서 json 객체를 만들어서 FinalCart.js로 넘겨주고 FinalCart.js에서는 받은 json 객체를 useState로 다루는 것으로 생각을 바꿔보았다.

왜냐하면 useState 없이 값이 바뀔 때 리렌더링이 되는 방법이 없다고 생각했기 때문이다.

 

 

Cart.js

import React from 'react';
import {Link} from 'react-router-dom';
import {useSelector} from 'react-redux';

function Cart() {
    const cart = useSelector((store) => store.cartReducer);
    const list = []; 
    const res = [];
    const arr = Object.create(null);
    let sum = 0;

    const cartItem = cart.length >= 1 ? cart.map((item, idx) => {
        sum += item.price;

        return (
            <div key={idx} item={item} idx={idx}>
                <div>{item.name_kor}</div>
            </div>
        );
    }) : <div>장바구니가 비어있습니다.</div>;

    for(let i = 0; i < cart.length; i++) { //json 객체로 만들기
        const json = Object.create(null);
        json.Id = cart[i].id;
        json.Name = cart[i].name_kor;
        json.Price = cart[i].price;

        list.push(json);
    }

    for(let i = 0; i < list.length; i++) { // 같은 id 객체 삭제 후, Quantity +1
        if(!arr[list[i].Id]) {
            res.push(list[i]);
        }
        arr[list[i].Id] = ((arr[list[i].Id] || 0) + 1);
    }

    for (let j = 0; j < res.length; j++) {
        res[j].Quantity = arr[res[j].Id];
    }

    return (
        <div>
            <br />
            <hr />
            <h3>장바구니 화면입니다.</h3>
            <div>
                {cartItem}
            </div>

            <div className='cartStyle'>
                <div>금 액 : {sum}</div><br />
                <Link to= {{
                    pathname: '/finalcart',
                    state: {sum, res},
                }}>
                    <div><button>결제하기</button></div>
                </Link>
            </div>
        </div>
    );
}

export default Cart;

이렇게 장바구니에 담기는 부분은 Redux로, 장바구니 수량 변경을 위해 리덕스로 만들어진 장바구니 리스트들을 json 객체로 변경하고, 중복 id 객체는 삭제 후 Qauntity 항목을 추가하면서 수량을 +1 씩 하는 구조로 바꾸었다. 결제하기 버튼을 누르면서 FinalCart.js로 결제할 금액인 sum과 주문 리스트 객체인 res를 넘겨주었다. 

 

 

 

FinalCart.js

import React, {useEffect, useState} from 'react';
import {useLocation} from 'react-router-dom';

function FinalCart() {
    const cart = useLocation();
    const [finalSum, setfinalSum] = useState(cart.state.sum); //sum 값 초기화
    const [finalRes, setfinalRes] = useState([]); //res를 받을 finalRes

    useEffect(() => {
        setfinalSum(finalSum);
        setfinalRes(cart.state.res);
    });


    const onIncrease = (idx) => {
        setfinalRes(finalRes[idx]['Quantity'] += 1);
        totalSum(finalRes);
    };

    const onDecrease = (idx) => {
        if(finalRes[idx].Quantity > 0) {
            setfinalRes(
                finalRes[idx]['Quantity'] -= 1,
            );
        } else {
            setfinalRes(
                finalRes[idx]['Quantity'] = 0,
            );
        }
        totalSum(finalRes);
    };

    const totalSum = (cart) => {
        let total = 0;

        Object.keys(cart).map((item) => {
            total += finalRes[item].Price * finalRes[item].Quantity;
        });
        setfinalSum(total);
    };

    const list = Object.keys(finalRes).map((item, idx) => {
        return (
            <div key={idx}>
                <div>{finalRes[item].Name}</div>
                <div>{finalRes[item].Price}</div>
                <div>{finalRes[item].Quantity}</div>
                <button onClick={() => onIncrease(idx)}>+</button>
                <button onClick={() => onDecrease(idx)}>-</button>
                <br /><br />
            </div>
        );
    });
    
    return (
        <div>
            <h3>최종 장바구니 화면입니다.</h3>
            <div>총 금 액 : {finalSum}</div>
            <br />
            <hr />
            <div>{list}</div>
        </div>
    );
}

export default FinalCart;

FinalCart.js에서는 uesState, uesEffect로 변경되는 값들을 관리, 리렌더링한다.

증감버튼에서는 해당 리스트의 인덱스 값을 보내 finalRes의 해당 인덱스의 Quantity 값을 변경하고, 그에 따른 가격도 변경하는 코드를 구현했다.

 

막상 보니까 그렇게 안어렵고 복잡하지않은데 저 부분을 해결하는데에 너무 오랜 시간이 들어서 조금 자괴감이 들었지만 해냈다는 것에 정말 만족한다^_^!!

 

 

 

 

 

+) Redux로 quantity를 변경하는 코드를 추가 구현했다

https://good-potato.tistory.com/entry/React-%EC%9E%A5%EB%B0%94%EA%B5%AC%EB%8B%88-%EC%88%98%EB%9F%89-%EB%B3%80%EA%B2%BD1-%EC%B5%9C%EC%A2%85

(전 블로그에서 2021.02.24 18:28에 작성된 글입니다.) 

반응형
Comments