본문 바로가기

클라이언트/React
[리액트(React)] Reducer, useReducer(Hook)

// Reducer 

- 하나 또는 그 이상의 복잡한 값을 더 단순한 형태로 만드는 함수

- JavaScript의 reduce 함수도 Reducer 이다.


// useReducer 

- state 관리 hook

- 이전 state를 바탕으로 state를 업데이트할 때, 함수 형식을 사용하여 복잡해지는 것을 해결해 준다.


1. useReducer 생성 및 선언

const [useReducer로 관리되는 state명, dispatch 함수명] = useReducer(Reducer함수명, [초기값]);


- dispatch 함수로는 action을 보낼 수 있는데, 이렇게 보내진 함수는 Reducer 기능에 사용된다.


2. Reducer 함수 정의

function Reducer함수명(state, action) {
  //처리  
  return state
}

3. dispatch 함수 정의

dispatch 함수명({
    type: 유형,
    payload: 필수값,
});


- dispatch 함수를 호출할 때마다 Reducer 함수가 실행된다.

- type: Reducer에서 각각의 액션을 구분하고 다르게 처리하기 위해 유형 속성을 사용한다.

- paylaod: 해당 액션이 실행되기 위해 필요로 하는 데이터를 전달한다.
  > 이름이 꼭 payload일 필요x

- 전달한 type과 payload 등은 Reducer 함수의 action으로 전달된다.


function shoppingCartReducer(state, action) {
  if (action.type === 'ADD_ITEM') {
    const updatedItems = [...state.items];

    const existingCartItemIndex = updatedItems.findIndex(
      (cartItem) => cartItem.id === action.payload,
    );
    const existingCartItem = updatedItems[existingCartItemIndex];

    if (existingCartItem) {
      const updatedItem = {
        ...existingCartItem,
        quantity: existingCartItem.quantity + 1,
      };
      updatedItems[existingCartItemIndex] = updatedItem;
    } 

    return {
      ...state,
      items: updatedItems,
    };
  }

  if (action.type === 'UPDATE_ITEM') {
    const updatedItems = [...state.items];
    const updatedItemIndex = updatedItems.findIndex(
      (item) => item.id === action.payload.productId,
    );

    const updatedItem = {
      ...updatedItems[updatedItemIndex],
    };

    updatedItem.quantity += action.payload.amount;

    if (updatedItem.quantity <= 0) {
      updatedItems.splice(updatedItemIndex, 1);
    }

    return {
      ...state,
      items: updatedItems,
    };
  }

  return state;
}

export default function CartContextProvider({ children }) {
  const [shoppingCartState, shoppingCartDispatch] = useReducer(
    shoppingCartReducer,
    {
      items: [],
    },
  );

  function handleAddItemToCart(id) {
    shoppingCartDispatch({
      type: 'ADD_ITEM',
      payload: id,
    });
  }

  function handleUpdateCartItemQuantity(productId, amount) {
    shoppingCartDispatch({
      type: 'UPDATE_ITEM',
      payload: {
        productId,
        amount,
      },
    });
  }

  const ctxValue = {
    items: shoppingCartState.items,
    addItemToCart: handleAddItemToCart,
    updateItemQuantity: handleUpdateCartItemQuantity,
  };

  return (
    <CartContext.Provider value={ctxValue}>{children}</CartContext.Provider>
  );
}