본문 바로가기
React

☺️ React Redux, Redux Toolkit / Zustand 비교하기

by frontChoi 2026. 9. 6.
반응형

😃 Redux

특징

  • 단방향 패턴
    • UI -> Action -> Reducer -> Store -> UI변경

역할

  • Store: 상태 저장
  • Action: 무슨일이 발생했는지
  • Reducer: Action보고 상태 변경

단점

전통적인 Redux
counter +1를 하나 만들기 위해

  1. ActionType선언
  2. Action Creator 생성
  3. Reducer작성
    1. store구성 (const store = createStore(countReducer))
  4. dispatch(increment()) 를 컴퍼넌트에서 선언
  5. 불변성 유지를 위한 작업이 번거러움

 

😏Redux Toolkit

Redux의 불편한점 개선을 한 버전

특징

  • ActionType 선언, Action Creator 생성 불필요
  • 보일러 플레이트 해결
    • 하나의 동작을 위해 여러코드를 변경해야한다는 점

장점

  • 별도의 ActionType , ActionCreator 생성 불필요
  • 내부적으로 불변성유지를 해줌
const counterSlice = createSlice({
  name: "counter",

  initialState: {
    value: 0
  },

  reducers: {
    increment(state) {
      state.value++
    },

    decrement(state) {
      state.value--
    }
  }
})
/*
  Redux 방식
  return {
  ...state,
  user: {
    ...state.user,
    profile: {
      ...state.user.profile,
      address: {
        ...state.user.profile.address,
        city: "Seoul"
      }
    }
  }
}
*/

/* Redux Kit 방식 */
state.user.profile.address.city = "Seoul"

 

단점

  • 과도한 오버엔지니어링
    • 단순 모달 띄우는 경우 많은 코드 작성
    const modalSlice = createSlice({
      name: "modal",
      initialState: {
        open: false
      },
      reducers: {
        openModal(state) {
          state.open = true
        },
        closeModal(state) {
          state.open = false
        }
      }
    })
    
    dispatch(openModal())
    
    const open = useSelector(
      state => state.modal.open
    )
    

 

😫React Tool Kit으로 Login 만들기

항목 역할

createSlice state/reducer/action 생성
configureStore store 생성
useAppSelector 타입이 적용된 state 조회
useAppDispatch 타입이 적용된 dispatch
PayloadAction<T> action payload 타입 지정
createAsyncThunk 비동기 로직/API 처리
RootState 전체 state 타입
Provider React에 Redux 연결

Login Store 만들기

import { createSlice, type PayloadAction } from "@reduxjs/toolkit";

interface LoginState {
  isLogin: boolean;
  email: string | null;
}
const initialState: LoginState = {
  isLogin: false,
  email: null,
};

const loginSlice = createSlice({
  name: "login",
  initialState,
  reducers: {
    login: (state, action: PayloadAction<string>) => {
      state.isLogin = true;
      state.email = action.payload;
    },
  },
});

// 컴포넌트에서 dispatch할 때 필요
export const { login } = loginSlice.actions;
// configureStore에 등록할 때 필요
export default loginSlice.reducer;

Login을 Store에 구성하기

import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
import loginReducer from "../features/login/loginSlice";
export const store = configureStore({
  reducer: {
    counter: counterReducer,
    login: loginReducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

Provider로 Store제공하도록 설정

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import "./index.css";
import App from "./App.tsx";
import { store } from "./app/store.ts";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </StrictMode>,
);

컴퍼넌트에 적용하기

import { useState, type SubmitEvent } from "react";
import "./App.css";
import { useDispatch } from "react-redux";
import { useSelector } from "react-redux";
import { login } from "./features/login/loginSlice";
import type { RootState } from "./app/store";
function App() {
  const [id, setId] = useState("");
  const dispatch = useDispatch();
  const loginState = useSelector((state: RootState) => state.login);
  const handleSubmit = (e: SubmitEvent<HTMLFormElement>) => {
    e.preventDefault();
    dispatch(login(id));
  };
  return (
    <>
      <form onSubmit={handleSubmit}>
        <label htmlFor="id">ID</label>
        <input
          id="id"
          name="id"
          type="text"
          placeholder="아이디를 입력하세요"
          value={id}
          onChange={(e) => setId(e.target.value)}
        />

        <button type="submit">로그인</button>
      </form>

      <p>{loginState.email}</p>
    </>
  );
}

export default App;

 

위와같이 redux toolkit으로 할려면

createSlice생성 및 PayloadAction선언 → store.ts에 등록 → 컴퍼넌트에서 상태갱신은 useDispatch, 상태조회는 useSelectors으로 확인 한다. 하나의 기능을 위해서 여러가지의 과정을 거쳐야 하는 단점이 존재한다

 

 

 

🦞 Zustand

Zustand는 JavaScript/TypeScript 애플리케이션에서 사용할 수 있는 가볍고 단순한 상태 관리 라이브러리

 

 

특징

  • Redux와 다르게 Action → dispatch → reducer구조가 아닌 Store → State + Action
  • dispatch필요 없음

역할

  • Store: State+Action을 동시에 관리(Redux처럼 Action을 따로 관리하지 않음)

Zustand으로 Login 만들기

코드 용어/역할/사용 예

create Store 생성 create<LoginStore>(...)
set State 변경 set({ isLogin: true })
get 현재 State 조회 get().isLogin
state 현재 Store의 상태 (state) => state.id
Store Hook Store 접근 + 구독 useLoginStore(...)
Selector 필요한 값을 선택 (state) => state.isLogin

LoginStore만들기

import { create } from "zustand";

interface LoginState {
  isLogin: boolean;
  email?: string;

  login: (email: string) => void;
}

export const useLogin = create<LoginState>((set) => ({
  isLogin: false,
  email: undefined,

  login: (email) => {
    set({
      isLogin: true,
      email,
    });
  },
}));

컴퍼넌트에서 사용하기

import { useState, type SubmitEvent } from "react";
import "./App.css";
import { useLogin } from "./features/login/loginStore";
function App() {
  const [id, setId] = useState("");
  const login = useLogin((state) => state.login);
  const email = useLogin((state) => state.email);

  const handleSubmit = (e: SubmitEvent<HTMLFormElement>) => {
    e.preventDefault();
    login(id);
  };
  return (
    <>
      <form onSubmit={handleSubmit}>
        <label htmlFor="id">ID</label>
        <input
          id="id"
          name="id"
          type="text"
          placeholder="아이디를 입력하세요"
          value={id}
          onChange={(e) => setId(e.target.value)}
        />

        <button type="submit">로그인</button>
      </form>

      <p>{email}</p>
    </>
  );
}

export default App;

위 처럼 Redux Tool kit 보다 코드양이 간소화 되었다.

코드양으로봐서는 장점이 확실히 있다.

개인적으로는 Store에 State/Actions을 관리하는것이 혼란을 주지 않을까 싶긴하다

반응형

'React' 카테고리의 다른 글

😀 React Custom Hook  (0) 2026.06.02
⚽️Zustand  (0) 2025.12.01
🍏 React Hook  (0) 2025.10.24

댓글