Reducer, Action, Dispatch

Jaeseok Han·2023년 11월 17일
0

Redux-Toolkit

목록 보기
5/6

Reducer

Reducer는 현재 상태와 액션을 받아서 새로운 상태를 반환하는 순수함수이다. Redux에서 상태의 변화를 처리하며 불변성을 유지하면서 상태를 업데이트해야 한다.

예시

const cartSlice = createSlice({
  name: 'cart',
  initialState,
  reducers: {
    clearCart: (state) => {
      state.cartItems = [];
    },
  },
});

export const { clearCart } = cartSlice.actions;

clearCart 라는 장바구니를 비우는 리듀서를 추가

Action

Action은 어떤 변화가 일어났는지 설명하는 객체이다. 애플리케이션에서 어떠한이벤트가 발생했음을 나타낸다.
일반적으로 type 속성을 가지고 있으며, 이를 통해 어떤 종류의 액션이 발생했는지를 식별한다. 그 외에 필요한 정보는 payload라는 속성을 통해 전달한다.

예시

const ACTION_TYPE = 'ACTION_TYPE';

const actionCreator = (payload) => {
  return { type: ACTION_TYPE, payload: payload };
};

ACTION_TYPE 은 액션의 타입을 나타내는 문자열 상수이다. 액션 객체에서 어떤 종류의 액션이 발생했는지 식별하는데 사용된다.
actionCreator는 액션을 생성하는 함수로 액션 객체를 반환한다

💡 Redux-Toolkit애서 Reducer와 Action
원래 Redux에서는 Action과 Reducer를 개별적으로 분리하여 사용하지만 Redux-Toolkit에서는 createSlice를 사용하여 reducer와 action을 함께 정의한다.
코드가 간결해지고 유지보수성을 향상시킨다.

Dispatch

Redux에서 액션을 발생시켜 리듀서에게 전달하는 함수이다. Redux 스토어의 메서드 중 하나로 애플리케이션의 상태를 업데이트하는데 사용된다.

  • 액션 전달
  • 리듀서 호출
  • 상태 업데이트
import React from 'react';
import CartItem from './CartItem';
import { removeItem } from '../features/cart/cartSlice';
import { useDispatch, useSelector } from 'react-redux';

const CartContainer = () => {
  const dispatch = useDispatch();

  return (
    <button
      className='btn clear-btn'
      onClick={() => {
        dispatch(clearCart());
      }}
    >
      clear cart
    </button>
  );
};
  • useDispatch 훅을 사용하여 dispatch를 통해 action(clearCart)를 스토어에 전달하여 어떤 작업을 할지에 대한 type을 나타내며 리듀서에게 전달된다.
  • 전달된 액션은 리듀서에 의해 처리되어 상태가 업데이트된다.
  • 업데이트된 상태는 Redux 스토어에저장되어 전체 애플리케이션의상태가 업데이트된다.

사용해보기

Remove, Increase, Decrease

삭제, 증가, 감소 기능을 Redux를 이용하여 만들어본다.

import { createSlice } from "@reduxjs/toolkit";
import cartItems from "../../cartItems";

const initialState = {
    cartItems : cartItems,
    amount : 4,
    total : 0,
    isLoading : true
}

const cartSlice = createSlice({
    name : 'cart',
    initialState,
    reducers: {
        clearCart: (state) => {
            state.cartItems = [];
        },
        removeItem : (state, action) => {
            const itemId = action.payload;
            state.cartItems = state.cartItems.filter((item) => item.id !== itemId);
        },
        increase: (state, { payload }) => {
            const cartItem = state.cartItems.find((item) => item.id === payload.id)
            cartItem.amount = cartItem.amount + 1
        },
        decrease: (state, { payload }) => {
            const cartItem = state.cartItems.find((item) => item.id === payload.id)
            cartItem.amount = cartItem.amount - 1
        },
    }
})

export const { clearCart, removeItem, increase, decrease } = cartSlice.actions;
 
export default cartSlice.reducer;

import React from 'react'
import { ChevronDown, ChevronUp } from '../icons'
import { removeItem, increase, decrease } from '../features/cart/cartSlice';
import { useDispatch } from 'react-redux';

const CartItem = ({id, img, title, price, amount}) => {
    const dispatch = useDispatch();
    return (
        <article className='cart-item'>
            <img src={img} alt={title}/>
            <div>
                <h4>{title}</h4>
                <h4 className="item-price">${price}</h4>
                <button className='remove-btn' onClick={() => {
                    dispatch(removeItem(id));
                }}>삭제</button>
            </div>
            <div>
                <button className='amount-btn' onClick={() => {
                    dispatch(increase({ id }))
                }}>
                    <ChevronUp/>
                </button>
                <p className='amount'>{amount}</p>
                <button className='amount-btn' onClick={() => {
                    dispatch(decrease({ id }))
                }}>
                    <ChevronDown/>
                </button>
            </div>
        </article>
    )
}

export default CartItem

onClick 이벤트로 삭제 증가 감소를 Redux를 통해 상태관리 하도록 하였다.

Total calcuation

App.js

import { useDispatch, useSelector } from "react-redux";
import CartContainer from "./components/CartContainer";
import Navbar from "./components/Navbar";
import { useEffect } from "react";
import { calculateTotals } from "./features/cart/cartSlice";

function App() {
  const { cartItems } = useSelector((state) => state.cart);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(calculateTotals())
  },[cartItems])

  return (
    <main>
      <Navbar/>
      <CartContainer/>
    </main>
  )
}
export default App;

carItems이 변경되면 자동으로 계산해줄 수 있도록 설정

   calculateTotals: (state) => {
      let amount = 0;
      let total = 0;
      state.cartItems.forEach((item) => {
        amount += item.amount;
        total += item.amount * item.price;
      });
      state.amount = amount;
      state.total = total;
    },

리듀서 추가

0개의 댓글