본문 바로가기

React 실습

리덕스 툴킷 사용 복습!

728x90

리덕스 툴킷을 이용하는 코드를 정리하는 글을 시작해보련다.

 

# 1. slice함수를 만든다. 

[cart-slice 코드]

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

// createSlice를 이용하여 초기값 초기화
const cartSlice = createSlice({
  name: "cart",
  initialState: {
    items: [],
    totalQuantity: 0,
    totalAmount: 0,
  },
  // 리듀서 함수 생성
  reducers: {
    // 리듀서 함수를 내가 쓸려도는 의도에 맞게 코드
    addItemToCart(state, action) {
      // 넘겨받는 매개변수에는 action.payload로 접근할 수 있다.
      // dispatch에서 전달해주는 매개변수들!!
      const newItem = action.payload;
      const existingItem = state.items.find((item) => item.id === newItem.id);
      state.totalQuantity++;
      if (!existingItem) {
        state.items.push({
          id: newItem.id,
          price: newItem.price,
          quantity: 1,
          totalPrice: newItem.price,
          name: newItem.title,
        });
      } else {
          existingItem.quantity++;
          existingItem.totalPrice = existingItem.totalPrice + newItem.price
          }
    },
    removeItemFromCart(state, action) {
      const id = action.payload;
      const existingItem = state.items.find(item => item.id === id);
      state.totalQuantity--;
      if (existingItem.quantity === 1) {
        state.items = state.items.filter(item => item.id !== id);
      } else {
        existingItem.quantity--;
        existingItem.totalPrice = existingItem.totalPrice - existingItem.price;
      }
    },
  },
});

// 액션함수 export
export const cartActions = cartSlice.actions;
// 슬라이스 export
export default cartSlice;

# 2. index.js 파일 store함수에서 리듀서들을 합친다.

 

import { configureStore } from '@reduxjs/toolkit';
import cartSlice from './cart-slice';

import uiSlice from './ui-slice'

// uiSlice 이전에 만든 리듀서함수다 이런식으로
// 리듀서들을 한곳으로 합쳐서 key를이용하여 이용할 수 있다
// key = ui, cart...
const store = configureStore({
    reducer: { ui: uiSlice.reducer, cart: cartSlice.reducer },
})

export default store;

 

# 3. 리듀서를 이용하려면 가장 최상단 루트 컴포넌트에 Provider로 감싸야 이용할 수 있다.

 

import ReactDOM from "react-dom";
import { Provider } from "react-redux";

import "./index.css";
import App from "./App";
// 여기서 sotre를 import 해줌으로써 아래의 자식들이 store를 이용할 수 있는 것
import store from "./store/index"

ReactDOM.render(
  // Provider로 감싸주고 store 이용
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

 

# 4. 이용하려는 컴포넌트로 가서 export 해서 이용할 slice함수.Action을 import 한다.

 

(만드려는 것)

현재 나는 더미 상품을 두개 만들어서 더미 상품에 있는 컴포넌트에서 add to cart버튼을 누르면 상품이 추가 되도록 만들 것이다.

 

현재 index.js > app.js > product, cart 

이런 스택으로 쌓여 있다. product 컴포넌트에서 더미 상품을 보여줄거다.

 

[product 코드]

 

import ProductItem from './ProductItem';
import classes from './Products.module.css';

const DUMMY_PRODUCTS = [
  {
    id: 'p1',
    price: 6,
    title: 'My First Book',
    description: 'The first book I ever wrote',
  },
  {
    id: 'p2',
    price: 7,
    title: 'My Second Book',
    description: 'The second book I ever wrote',
  },
];

const Products = (props) => {
  return (
    <section className={classes.products}>
      <h2>Buy your favorite products</h2>
      <ul>
        {DUMMY_PRODUCTS.map((product) => (
          <ProductItem
            key={product.id}
            id={product.id}
            title={product.title}
            price={product.price}
            description={product.description}
          />
        ))}
      </ul>
    </section>
  );
};

export default Products;

 

이제 productItem에 key, id, title, price, description이 전달 되니 이를 활용할 수 있다.

product > productItem 컴포넌트에서 add to cart 버튼을 누르면 상품이 하나씩 추가되게 할 것임.

 

- useDispatch를 이용하여 액션함수에 접근할 것이고,

import { useDispatch } from 'react-redux';

- 만들어논 액션함수를 import 할 것이다.

import { cartActions } from '../../store/cart-slice';

 

[ProducItem.js 코드]

 

import { useDispatch } from 'react-redux';

import { cartActions } from '../../store/cart-slice';
import Card from '../UI/Card';
import classes from './ProductItem.module.css';

const ProductItem = (props) => {
  const dispatch = useDispatch();
  
  // proudct.js 에서 전달 받는 props 데이터를 이용
  const { title, price, description, id } = props;

  const addToCartHandler = () => {
    // dispatch slice함수에서 정의해논 액션 함수를 이용 + 매개변수 전달
    // slice함수에서는 action.payload로 해당 변수들을 받아서 이용하는 것
    dispatch(
      cartActions.addItemToCart({
        id,
        title,
        price,
      })
    );
  };

  return (
    <li className={classes.item}>
      <Card>
        <header>
          <h3>{title}</h3>
          <div className={classes.price}>${price.toFixed(2)}</div>
        </header>
        <p>{description}</p>
        <div className={classes.actions}>
          // 이버튼을 누르면 onClick에의해 핸들러함수가 작동
          <button onClick={addToCartHandler}>Add to Cart</button>
        </div>
      </Card>
    </li>
  );
};

export default ProductItem;

 

# 5. 이제 store에 모아둔 state값들이 상호작용 한다. 이제 이것들을 이용할 컴포넌트로 가서 사용하자

useSelector을 통해 접근할 수 있다.

 

// state 상태르 접근하고 cart는 store에서 지정한 key값이다
// 이 key값으로 해당 state에 값을 접근하는 것
// 지금 카트 바구니의 총수량을 업데이트할 것이므로 totalQuantity로 접근하는 것
useSelector((state) => state.cart.totalQuantity);

[cartButton 코드] 

* 해당 state를 이용하는 컴포넌트

 

import { useDispatch, useSelector } from 'react-redux';

import { uiActions } from '../../store/ui-slice';
import classes from './CartButton.module.css';

const CartButton = (props) => {
  const dispatch = useDispatch();
  // state를 조회해서 변수에 저장
  const cartQuantity = useSelector((state) => state.cart.totalQuantity);

  const toggleCartHandler = () => {
    dispatch(uiActions.toggle());
  };

  return (
    <button className={classes.button} onClick={toggleCartHandler}>
      <span>My Cart</span>
      // 변수 기입
      <span className={classes.badge}>{cartQuantity}</span>
    </button>
  );
};

export default CartButton;

 

 

정리

  • add to cart 버튼을 누르는 순간
  • 핸들러 함수(addToCartHandler)가 작동되고
  • 핸들러 함수는 useDispatch 훅를 이용하여 리듀서함수(addItemToCart)를 작동시킨다 (리듀서 함수에서 내가 원하는 작동을 정의 하면 된다.)
  • 그러면 state가 최신화 되고
  • 사용하려는 컴포넌트(cartButton)로 가서 useSeletor를 이용하여 store에 정의된 key를 이용하여 state에 접근하여 state를 가져오면 된다.

 

728x90