43, 44일차 React 상태관리, Redux

2021. 9. 17. 23:49
반응형

2021. 09. 17 금요일

1. Today's Key Points!🔑

  • state
  • Redux

2. 정리해보자!🧹

상태 관리 라이브러리를 사용하는 이유?

React에서 최상위 컴포넌트에서 state를 관리하고, 하위 컴포넌트에서 사용하려면 props로 넘겨받아와서 사용해야 한다.

근데 state가 관리되는 컴포넌트와 state를 사용하려는 컴포넌트 사이에 10개의 컴포넌트가 존재한다고 가정하면 props로 10번 넘겨주고 받아야 사용을 할 수 있다.

이렇게 컴포넌트간의 연결이 복잡한 애플리케이션 일수록 props를 넘겨주고 받는것이 굉장히 번거로워질 수 있다.

state를 한 저장공간에 담아놓고 필요할 때 마다 꺼내쓸 수 있도록 하면 props를 넘겨주고 넘겨주고 하는 번거로움이 사라질 수 있을 것이다.

그래서 상태 관리 라이브러리를 사용하면 그 문제점을 해결 할 수 있다.

상태 관리를 위한 각종 툴이 있는데, 우리는 Redux를 사용할 것이다.

리덕스에 대한 기본 개념은 따로 페이지를 만들어 정리할 것이다.

3. Sprint과제 복기!🧐

43일차에는 그냥 props를 전달해주는 방식으로 상품리스트를 장바구니에 담기게 해주는 애플리케이션을 구현해보았다.

그리고 오늘은 Redux를 이용해서 같은 애플리케이션을 구현했다.

우선 Redux를 사용하기 이전에 하나의 공식처럼 알고 있어야하는 것이 있다.

Action 객체는 Dispatch 메소드에게 전달되고, Dispatch는 Reducer를 호출해서 새로운 state를 생성한다는 것이다.

그렇기 때문에 우선 Store에게 우리 애플리케이션의 데이터를 운반해줄 Action객체를 먼저 만들어 준다.

...

// actions creator functions
export const addToCart = (itemId) => {
  return {
    type: ADD_TO_CART,
    payload: {
      quantity: 1,
      itemId
    }
  }
}

export const removeFromCart = (itemId) => {
  return {
    type: REMOVE_FROM_CART,
    payload: { 
      itemId
    }
  }
}

export const setQuantity = (itemId, quantity) => {
  return {
    type: SET_QUANTITY,
    payload: {
      itemId,
      quantity
    }
  }
}

...

카트에 상품리스트를 담아줄 Action, 카트로부터 상품리스트를 삭제해줄 Action, 카트에 상품리스트의 갯수를 변경해줄 Action을 만들었다.

그럼 이제 Dispatch에게 호출당해야하는 Reducer를 만들자.

Reducer는 현재 상태와 Action을 이용해서 state를 변경시켜주는 역할을 담당한다.

import { REMOVE_FROM_CART, ADD_TO_CART, SET_QUANTITY } from "../actions/index";
import { initialState } from "./initialState";

const itemReducer = (state = initialState, action) => {

  switch (action.type) { //액션 타입이
    case ADD_TO_CART: //ADD_TO_CART 이면
      return Object.assign({}, state, {
        cartItems: [...state.cartItems, action.payload]
      })

    case REMOVE_FROM_CART: //REMOVE_FROM_CART 이면
      return Object.assign({}, state, {
        cartItems: state.cartItems.filter((el) => el.itemId !== action.payload.itemId)
      })

    case SET_QUANTITY: //SET_QUANTITY 이면
      let idx = state.cartItems.findIndex(el => el.itemId === action.payload.itemId)
      state.cartItems[idx].quantity = action.payload.quantity
      return Object.assign({}, state, {
        cartItems: state.cartItems
      })

    default:
      return state;
  }
}

export default itemReducer;

여기서 주의해야할 점은 state를 immutable하게 관리를 해주어야 한다는 것이다.

즉, Reducer는 순수함수가 되어야 한다. 그리고 위의 코드는 switch문으로 작성되었지만 if문으로 작성해도 무방하다.

그리고 state가 관리되는 Store(저장소)를 createStore 메소드를 활용해서 reducer를 연결해준다.

const store = createStore(rootReducer);

실제 과제의 js파일에는 Reducer를 여러파일에 만들어서 rootReducer로 병합을 시켜준뒤 store에 연결시켜 주었다.

그럼 이제 Redux hooks로 필요한 기능을 구현시켜 보자.

Redux hooks에서는 크게 useSelector(), useDispatch() 이 두가지 메소드를 기억하면 된다.

간단하게 useSelector()는 state와 연결시켜주는 메소드이고, useDispatch()는 Action객체를 Reducer로 전달해주는 메소드이다.

...
//장바구니 담기
function ItemListContainer() {
  const state = useSelector(state => state.itemReducer); //useSelector메소드로 컴포넌트와 state를 연결해주었다.
  const { items, cartItems } = state;
  const dispatch = useDispatch(); //useDispatch메소드를 통해 Action객체를 Reducer로 전달해준다.

  const handleClick = (item) => {
    if (!cartItems.map((el) => el.itemId).includes(item.id)) {
      dispatch(addToCart(item.id))//dispatch로 'ADD_TO_CART' Action객체를 호출해 실행시켜준다.
      dispatch(notify(`장바구니에 ${item.name}이(가) 추가되었습니다.`))
    }
    else {
      dispatch(notify('이미 추가된 상품입니다.'))
    }
  }
  ...
...
//장바구니에서 상품리스트 삭제, 수량 변경
export default function ShoppingCart() {

  const state = useSelector(state => state.itemReducer);
  const { cartItems, items } = state
  const dispatch = useDispatch();
  const [checkedItems, setCheckedItems] = useState(cartItems.map((el) => el.itemId))

//중략

  const handleQuantityChange = (quantity, itemId) => {
    dispatch(setQuantity(itemId, quantity))
  }

  const handleDelete = (itemId) => {
    setCheckedItems(checkedItems.filter((el) => el !== itemId))
    dispatch(removeFromCart(itemId))
  }
...

이렇게 Action객체와 Reducer를 만들어놓고 한 저장공간Store에 state를 저장시켜 놓은뒤에 필요한 것만 꺼내쓰면 된다.

이번 과제는 그렇게 복잡하지 않은 구성이라 크게 와닿지 않을 수 있겠지만, 여기서 결제창, 로그인창 등등 더 추가된 애플리케이션이면 점점 구조가 복잡해질 것이고 그때 props를 일일이 전달해주는 방식으로 구현을 하면 작업이 더 복잡해 질 수 있을 것이다. 

 

반응형
LIST

BELATED ARTICLES

more