감자튀김 공장🍟

[React] Redux 장바구니 수량 변경2 (최종) 본문

Study/React

[React] Redux 장바구니 수량 변경2 (최종)

Potato potage 2021. 3. 29. 15:17
반응형

폴더 구조

src
|
|- component
|	|- Cart.js
|	|- FinalCart.js
|
|- pages
|	|-MenuList.js

 

 

 

 

 

pages/MenuList.js

import React, {useState, useEffect} from 'react';
import axios from 'axios';
import {useDispatch} from 'react-redux';
import {addCart} from '../store/actions';

function MenuList(props) {
    const [products, setProducts] = useState([]);
    const dispatch = useDispatch();
    const list2 = []; 

    useEffect(() => { // DB에서 데이터를 받아온다.
        axios.get('/api/menus').then((res) => setProducts(res.data));
    }, []);

    const list = products.filter((res) => { // 카테고리별로 아이템을 띄운다.
        return res.category_id === props.categoryId;
    });

    for(let i = 0; i < list.length; i++) { // list2에 DB에서 받아온 정보들을 아래와 같이 가공한다.
        const json = Object.create(null);
        json.Id = list[i].id;
        json.Name = list[i].name_kor;
        json.CategoryId = list[i].category_id;
        json.Img = list[i].img_url;
        json.Price = list[i].price;
        json.Description = list[i].description;
        json.Quantity = 1;

        list2.push(json);
    }
    
    return ( // 메뉴 출력
        <div>
            {
                list2.map((item) => {
                    return (
                       <div className="menuItem" onClick={() => dispatch(addCart(item))}>
                            <div className="itmeName">{item.Name}</div>
                       </div>
                    );
                })
            }
        </div>
    );
}

export default MenuList;

전에는 DB에서 가져온 데이터를 store에 그대로 넣고 FinalCart.js에서는 store에서 cart를 받아와 가공하여 사용을 했더니 (중복 아이템을 없애고 Quantity를 추가하기 위함이었다.) redux의 delete가 먹히질 않았다.

그래서 아예 처음부터 DB를 가공해 store에 저장해 추가,삭제,수량 증감까지 한 번에 사용할 수 있도록 했다. (전에는 수량 같은 경우를 redux로 처리한 것이 아니었다.)

 

 

해당 div를 누르면 dispatch를 통해 addCart가 일어날 수 있도록 하였다. 즉 장바구니에 제품이 담기게 되는 것이다.

 

MenuList.js 페이지(상단~)와 Cart.js(하단부) 페이지

 

 

 

component/Cart.js

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

function Cart() {
    const list = useSelector((store) => store.cartReducer);
    
    const cartItem = list.cart.map((item, idx) => {
        return (
           // cartItem 출력
        );
    });

    return (
        <>
            <CartMenus>
                {cartItem}   
            </CartMenus>

            <CartSum>
                <!-- finalCart.js로 이동하는 버튼 및 total 값 출력 -->
            </CartSum>
        </>
    );
}

export default Cart;

Cart.js에서는 useSelector를 이용해 구독하고 있는 store에서 cart를 가져와 내용을 출력한다.

위의 사진에서 아래 하단부가 Cart.js이고 MenuList.js에서 메뉴를 클릭할 때 dispatch가 실행되면서 action을 일으키고 useSelector를 이용하여 Cart.js에서 구독하고 있는 store의 데이터를 가져와 페이지에 출력한다.

 

 

 

 

component/FinalCart.js

import React from 'react';
import {Steps, Divider, Button} from 'antd';
import {MinusOutlined, PlusOutlined} from '@ant-design/icons';
import {useDispatch, useSelector} from 'react-redux';
import {deleteCart, increment, decrement} from '../store/actions';

function FinalCart() {
    const {Step} = Steps;
    const ButtonGroup = Button.Group;
    const dispatch = useDispatch();
    const cart2 = useSelector((store) => store.cartReducer);

    const list = cart2.cart.map((item, idx) => {
        return (
            <div key={idx} className='item' item={item}>
                <Button className='delete' type='text' onClick={() => dispatch(deleteCart(item))}>x</Button>
                <div className='itemName'>{item.Name}</div>
                <ButtonGroup className='button'>
                    <Button onClick={() => dispatch(decrement(item))} min={1}>
                        <MinusOutlined />
                    </Button>
                    <Button>
                        {item.Quantity}
                    </Button>
                    <Button onClick={() => dispatch(increment(item))}>
                        <PlusOutlined />
                    </Button>
                </ButtonGroup>
                <div className='price'>{item.Price * item.Quantity}</div>
                <Divider className='divider'/>
            </div>
        );
    });

    return (
        <>
            <Header/>
            <!-- 다른 추가 내용 렌더링 -->
        </>
    );
}

export default FinalCart;

Cart.js와 같이 useSelector를 통하여 store의 내용을 가져와 출력하는데 Cart.js와는 다르게 img도 없고 이름과 가격, 개수만 출력한다.

<Button>에서 dispatch를 통해 상품 증/감을 할 수 있도록 되어있다.

 

 

 

FinalCart.js

 

 

redux가 막상 어려워 보여서 redux로 데이터 관리를 하기 싫었었는데 막상 도입하니까 렌더링도 금방금방 되어서 보기  편한 것 같고 좋다. 

 

 

 

 

왜 한 달 전에 만든 리덕스에서는 아이템 삭제가 안된 건가 곰곰이 생각해보았는데 그때는 아무래도 redux store에 저장한 값은 Cart.js에 있는데 그 데이터를 1차 가공하여 FinalCart.js에서 사용하니까 객체가 달라서 삭제하는 것이 안됐었던 것 같다. 그래서 이번에는 redux에서 중복 검사와 Quantity 조절까지 다 할 수 있도록 코드를 개선했더니 굳이 Cart.js에서 FinalCart.js로 데이터를 가공하여 넘겨줄 필요가 없어 같은 객체를 계속하여 사용하기 때문에 제품 삭제도 수량 증감도 잘 되는 것 같다. 

반응형
Comments