104일차 - React (Redux - useState의 대체제)

Yohan·2024년 7월 26일
0

코딩기록

목록 보기
146/156
post-custom-banner

기존 useState 장단점

장점

  • 기존에 useState로 상태관리를 했다.
  • 추가 라이브러리 없이 React만을 이용해 사용가능
  • 간단하고 직관적이며 독립적

단점

  • 복잡해지고 사이즈가 커지면 상태 관리가 어려움
  • 상태 공유가 어려워서 상태를 여러 컴포넌트에서 공유하려면 context API를 사용해야함

Redux의 장단점

장점

  • 중앙에서 관리 가능
  • 확장성이 좋아 큰 애플리케이션에서 상태를 효율적으로 관리
  • Redux 미들웨어를 사용하여 로깅, 비동기 요청 등을 쉽게 처리할 수 있음

단점

  • 복잡성이 증가
  • redux 따로 공부해야됨

결론

  • 작은 애플리케이션은 useState와 useReducer가 충분
  • 중간 ~ 큰 애플리케이션은 여러 컴포넌트 간 상태 공유가 많고 상태가 복잡하다면 Redux를 사용

Redux 흐름

  1. 스토어(Store) 생성 : 중앙 상태 저장소를 생성
  • createStore 또는 configureStore 함수를 사용하여 생성
  1. 리듀서(Reducer) 업데이트 - (slice.js)
  • 액션을 처리하고 상태를 업데이트하는 함수. 리듀서는 현재 상태와 액션 객체를 입력으로 받아 새로운 상태를 반환
  1. 컴포넌트에서 상태 사용
  • useSelector는 useState의 변수,
  • useDispatch는 useState의 setter 같은 개념.
  • useSelectoruseDispatch를 사용하여 컴포넌트에서 상태를 사용하고 변경

실습

store/index.js

  • 스토어 생성
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";
import authReducer from "./authSlice";

// 단하나의 리덕스 스토어
// 스토어에는 여러 리듀서를 제공할 수 있다.
const store = configureStore({
  reducer: {
    counter: counterReducer,
    auth: authReducer,
  },
});

// 리액트의 index.js에게 store를 제공
export default store;

index.js

  • 상위 index.js에게 store 제공
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import store from "./redux-cart/store/index";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

counterSlice.js

  • 액션을 처리하고 상태를 업데이트. 리듀서는 현재 상태와 액션 객체를 입력으로 받아 새로운 상태를 반환

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

// 관리할 초기 상태값 객체
const initialCountState = {
  counter: 0,
  showCounter: true,
};

// reducer: 상태 변경을 위한 순수 함수 - 부수 효과(비동기코드...)가 없는 함수
// 카운터 상태 관리를 위한 리듀서 정의
/*
    param1 (state): 상태 변경 이전의 상태
    param2 (action): 상태를 어떻게 변경할지의 대한 명세
    return - 변경 후 새로운 상태값
*/

// reducer를 slice로 변경
/*
  option객체에 들어가있는 프로퍼티 설명
  prop1: name - 컴포넌트가 해당 리듀서를 사용할 때 부르는 이름
  prop2: initialState - 관리할 상태값들의 초기값
  prop3: reducers - 기존 리듀서에서 사용하던 내용들(실제 액션)
*/
const counterSlice = createSlice({
  name: 'counter',
  initialState: initialCountState,
  reducers: {
    increment(state) {
      state.counter++;
    },
    decrement(state) {
      state.counter--;
    },
    multiply(state, action) {
      // console.log('state: ', state);
      // console.log('action: ', action);
      state.counter *= action.payload;
    },
    toggle(state) {
      state.showCounter = !state.showCounter;
    },
  }
});

// 슬라이스 안에 reducers에 정의한 함수들을 내보내기
export const counterActions = counterSlice.actions;
export default counterSlice.reducer;

ReduxCounter.js

  • useSelector 훅을 사용하여 Redux 스토어의 상태를 가져오거나 useDispatch 훅을 사용하여 상태값 변경
  • 액션은 꼭 dispatch로 묶어서 전송
import React from 'react';
import styles from './ReduxCounter.module.css';
import { useDispatch, useSelector } from 'react-redux';
import { counterActions } from '../store/counterSlice';

const ReduxCounter = () => {

  // useSelector라는 훅을 통해 redux store에 있는 상태값을 가져옴
  const counter = useSelector(state => state.counter.counter);
  const show = useSelector(state => state.counter.showCounter);

  // 리덕스 스토어에 상태값 변경을 위해 액션을 호출하는 훅
  const dispatch = useDispatch();

  const { increment, decrement, multiply, toggle } = counterActions;

  const increaseHandler = e => {
    // redux store에 접근해서 상태값을 변경시켜야 함
    // 리덕스에서는 상태값 변경을 위해 액션함수를 호출해야 함.
    // 액션 함수는 리덕스 스토어 내부에 있는 리듀서가 가지고 있음.
    
    // dispatch에는 인자로 어떤 변경을 할지 type과 변경에 필요한
    // payload를 전송
    dispatch(increment());
  };

  const decreaseHandler = e => {
    dispatch(decrement());
  };

  const multiplyHandler = e => {
    dispatch(multiply(2));
  };

  const toggleHandler = e => {
    dispatch(toggle());
  };

  return (
    <main className={styles.counter}>
      <h1>Redux Counter</h1>

      {show && <div className={styles.value}>{counter}</div>}
      
      <div>
        <button onClick={increaseHandler}>Increment</button>
        <button onClick={decreaseHandler}>Decrement</button>
        <button onClick={multiplyHandler}>IncrementDouble</button>
      </div>
      
      <button onClick={toggleHandler}>Toggle Counter</button>
    </main>
  );
};

export default ReduxCounter;

  • 여러 리듀서를 제공할 수 있는 store를 만들고
  • 필요한 slice를 만들어 초기값설정, reducers는 현재 상태와 액션 객체를 입력으로 받아 새로운 상태를 반환하고 export로 내보냄
  • 상태 관리가 필요한 컴포넌트에서 useSelector, useDispatch를 통해 사용
profile
백엔드 개발자
post-custom-banner

0개의 댓글