감자튀김 공장🍟

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

Study/React

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

Potato potage 2021. 3. 29. 14:31
반응형

폴더 구조

src
|
|- store
	|
	|- actions
	|	|
	|	|- index.js
	|
	|- reducers
		|
		|- cartReducer.js
		|- index.js

 

 

store/actions/index.js

export const addCart = (item) => {
    return {
        type: 'ADD_ITEM',
        payload: item,
    };
};

export const deleteCart = (item) => {
    return {
        type: 'DELETE_ITEM',
        payload: item,
    };
};

export const increment = (item) => {
    return {
        type: 'INCREMENT',
        payload: item,
    };
};

export const decrement = (item) => {
    return {
        type: 'DECREMENT',
        payload: item,
    };
};

redux로 장바구니에 아이템을 추가/삭제하는 것과 아이템의 수량까지 변경할 수 있도록 actions/index.js를 수정했다.

변경 전에는 redux로 장바구니에 아이템만 추가되는 기능이 있었고 수량 변경 같은 경우에는 redux으로 변경하는 것이 아니라 component에서 따로 변경했기 때문에 수량이 변경될 때마다 계속 렌더링이 일어났었다. 화면도 수량 변경할 때마다 깜빡깜빡 거리길래 다 redux로 처리해보자!라는 마음으로 다시 재수정에 들어갔다.

 

따라서 actions/index.js에는 아이템 추가, 삭제와 수량 증감을 위한 increment, decrement 함수를 작성해놓았다.

 

 

 

 

store/reducers/index.js

import {combineReducers} from 'redux';
import cartReducer from './cartReducer';

export default combineReducers({cartReducer});

전과 딱히 달라진 점은 없지만 일단 추가해놓았다.

 

 

 

 

 

store/reducers/cartReducer.js

const INITIAL_STATE = {
    cart: [],
    total: 0,
};

먼저 item들을 저장할 cart 배열과 가격을 저장할 total값을 INITIAL_STATE로 지정했다.

 

 

 

 case 'ADD_ITEM':
        const cartitem = state.cart.find((item) => item.Id === action.payload.Id);

        if (cartitem) {
            cartitem.Quantity += action.payload.Quantity;
        } else {
            const addtoCart = {
                Id: action.payload.Id,
                Img: action.payload.Img,
                Name: action.payload.Name,
                Price: action.payload.Price,
                Quantity: 1,
            };
            state.cart.push(addtoCart);
        }

        return {
            ...state,
            cart: [...state.cart],
            total: state.total + action.payload.Price,
        };

cart에 추가되는 item은 'ADD_ITEM'으로 실행되는데 component 구성은 다음 포스팅에서 다루겠지만 장바구니가 1,2차로 나뉘어져있다. 1차는 메뉴를 고를 수 있는 메뉴 페이지에서 메뉴와 같이 한눈에 볼 수 있고, 2차 장바구니는 메뉴 페이지 없이 장바구니에 담아놓은 물건들만 볼 수 있으며 이 페이지에서 수량 변경, 삭제까지 가능하다.

 

 

그래서 일단 같은 cart에 있는 id와 클릭한 물건의 id가 같은지 비교한 후, id가 같다면 그 id의 Quantity를 ++하고, id가 같지 않다던가 cart에 해당 id가 없다면 state.cart에 해당 아이템을 저장한다. 즉, 같은 상품을 계속하여 새로 저장하는 것이 아니라 이미 장바구니에 중복된 상품이 있다면 그 상품의 Id를 확인하고 Quantity를 증가시키는 것이다.

 

total는 현재 state.total값에 액션이 일어난 제품의 price값을 더하여 변경한다.

 

 

 

 case 'DELETE_ITEM':
        return {
            ...state,
            cart: state.cart.filter((item) => item.Id !== action.payload.Id),
            total: state.total - (action.payload.Price * action.payload.Quantity),
        };

상품을 지우는 'DELETE_ITEM' 액션이 일어나면 filter함수를 통해 액션이 일어난 제품의 Id와 cart속의 Id를 비교하여 해당 Id 제품을 삭제하고, total값도 해당 가격만큼 뺀다.

 

 

 

 

case 'INCREMENT': 
        const plus = state.cart.find((item) => item.Id === action.payload.Id);
        
        if (plus) {
            plus.Quantity += 1;
        }

        return {
            ...state,
            cart: [...state.cart],
            total: state.total + action.payload.Price,
        };
    case 'DECREMENT':
        const minus = state.cart.find((item) => item.Id === action.payload.Id);
        
        if (minus && minus.Quantity > 1) {
            minus.Quantity -= 1;

            return {
                ...state,
                cart: [...state.cart],
                total: state.total - action.payload.Price,
            };
        } else {
            return {
                ...state,
                cart: [...state.cart],
                total: state.total,
            };
        }

수량 증감을 위한 부분이다.

'INCREMENT'에서는 find함수를 사용하여 cart에 클릭한 제품의 Id와 같은 Id가 있는지 확인하고, Id가 있다면 해당 제품의 Quantity를 1 추가한다. total값도 해당 Id의 Price만큼 값을 더한다.

'DECREMENT'에서도 find 함수를 사용해 cart와 클릭한 제품의 Id를 비교하고, cart에 있는 제품이 1보다 클 경우에만 1씩 감소가 될 수 있도록 했다. 만약 cart에 있는 아이템의 개수가 1이라면 감소 버튼을 눌러도 더 삭제되지는 않는다.

 

 

 

 

따라서 최종 cartReducer.js 코드를 보자면

const INITIAL_STATE = {
    cart: [],
    total: 0,
};

const cartReducer = (state = INITIAL_STATE, action) => {
    switch(action.type) {
    case 'ADD_ITEM':
        const cartitem = state.cart.find((item) => item.Id === action.payload.Id);

        if (cartitem) {
            cartitem.Quantity += action.payload.Quantity;
        } else {
            const addtoCart = {
                Id: action.payload.Id,
                Img: action.payload.Img,
                Name: action.payload.Name,
                Price: action.payload.Price,
                Quantity: 1,
            };
            state.cart.push(addtoCart);
        }

        return {
            ...state,
            cart: [...state.cart],
            total: state.total + action.payload.Price,
        };
    case 'DELETE_ITEM':
        return {
            ...state,
            cart: state.cart.filter((item) => item.Id !== action.payload.Id),
            total: state.total - (action.payload.Price * action.payload.Quantity),
        };
    case 'INCREMENT': 
        const plus = state.cart.find((item) => item.Id === action.payload.Id);
        
        if (plus) {
            plus.Quantity += 1;
        }

        return {
            ...state,
            cart: [...state.cart],
            total: state.total + action.payload.Price,
        };
    case 'DECREMENT':
        const minus = state.cart.find((item) => item.Id === action.payload.Id);
        
        if (minus && minus.Quantity > 1) {
            minus.Quantity -= 1;

            return {
                ...state,
                cart: [...state.cart],
                total: state.total - action.payload.Price,
            };
        } else {
            return {
                ...state,
                cart: [...state.cart],
                total: state.total,
            };
        }
    default:
        return state;    
    }
};

export default cartReducer;

 

이렇게 되어있다.

 

 

 

다음 포스팅에는 어떤 component에서 dispatch를 하고 useSelectore를 했는지 적도록 하겠다.

반응형
Comments