본문 바로가기

Front-End/React

React #23 (훅, 상태관리 - 내장 useReducer vs Redux 패키지)

반응형

 

(본 글은 아래 링크의 내용을 기반으로 작성되었으니 참고해주세요.)

https://github.com/yisj777s/doit-react-webapp-typescript/tree/main/ch05/ch05_1

 

(더 자세하게 알고 싶으신 분은 이쪽으로...)

https://github.com/2jisu/do-it-react-with-ts/blob/main/Chapter05/chapter05.md

 

 

 

실제로 어떻게 동작시킬 건지에 대한 함수인 action을 정의하고 dispatch로 함수를 실행시켜서,

 

리듀서에 전달시키고, Redux에 저장. provider로 자식 컴포넌트에 props를 전달.

 

 

 

 

 

 

기본 문법

const [상태, dispatch] = useReducer(리듀서, 상태_초깃값)

 

 

 

 

src/store/

store/
├── actions.ts      → "뭘 할건지" 정의 (동작 함수 정의)
├── AppState.ts     → "전체 상태 구조" 정의 (어떤 데이터들이 있는지, 타입 정의)
├── index.ts        → "스토어 설정" (모든 걸 합쳐서 스토어 만들기)
├── rootReducer.ts  → "상태 변경 로직" 모음 (실제로 상태를 어떻게 바꿀지, switch/case 지정)
└── useStore.ts     → "편리한 사용법" (컴포넌트에서 쉽게 쓸 수 있게, 커스텀 훅 느낌)
더보기

actions.ts

import type { Action } from "redux"

export type SetTodayAction = Action<'setToday'> & {
    today: Date
}

export type Actions = SetTodayAction

 

AppState.ts

export type AppState = {
    today: Date
}

 

rootReducer.ts

import type { Actions } from './actions'
import type { AppState } from './AppState'

const initialAppState = {
    today: new Date()
}

export const rootReducer = (state: AppState = initialAppState, action: Actions) => {

    switch (action.type) {
        case 'setToday': {
            return {...state, today: action.today}
        }
    }
    return state
}

 

useStore.ts

import { configureStore } from '@reduxjs/toolkit'
import { useMemo } from 'react'
import { rootReducer } from './rootReducer'


const initializeStore = () => {
    const store = configureStore({
        reducer: rootReducer,
        middleware: getDefaultMiddleware => getDefaultMiddleware()
    })
    return store
}


export function useStore() {
    const store = useMemo(() => initializeStore(), [])
    return store
}

 

index.ts

export * from './AppState'
export * from './useStore'

 

 

src/pages/

더보기

UseReducerClock.tsx

import { useReducer } from "react";
import type { AppState } from "../store";
import { SetTodayAction } from "../store/actions";
import { Div, Title, Subtitle } from "../components";
import { useInterval } from "../hooks";


export default function UseReducerClock() {
  const [{today}, dispatch] = useReducer(
    (state: AppState, action: SetTodayAction) => {
      switch (action.type) {
        case 'setToday':
          return {...state, today: new Date()}
      }
      return state
    },
    {
      today: new Date()
    }
  )


  useInterval(() => {
    dispatch({type: 'setToday', today: new Date()})
  })

  return(
    <Div className="flex flex-col items-center justify-center mt-16">
      <Title className="text-5xl">UseReducerClock</Title>
      <Title className="mt-4 text-3xl">{today.toLocaleTimeString()}</Title>
      <Subtitle className="mt-4 text-2xl">{today.toLocaleDateString()}</Subtitle>
    </Div>
  )
}

 

ReduxClock.tsx

import { useSelector, useDispatch } from "react-redux";
import type { AppState } from "../store";
import { Div, Title, Subtitle } from "../components";
import { useInterval } from "../hooks";


export default function ReduxClock() {
  const today = useSelector<AppState, Date>(state => state.today)
  const dispatch = useDispatch()

  useInterval(() => {
    dispatch({type: 'setToday', today: new Date()})
  })

  return(
    <Div className="flex flex-col items-center justify-center mt-16">
      <Title className="text-5xl">ReduxClock</Title>
      <Title className="mt-4 text-3xl">{today.toLocaleTimeString()}</Title>
      <Subtitle className="mt-4 text-2xl">{today.toLocaleDateString()}</Subtitle>
    </Div>
  )
}

 

 

 

 

 

 

비교

좌: useReducer / 우: Redux

 

기본 정보

정의 React 내장 Hook 독립적인 상태 관리 라이브러리
설치 별도 설치 불필요 npm install redux react-redux
번들 크기 0kb (React 내장) ~47kb (Redux + React-Redux)

사용 방법 및 특징

상태 범위 컴포넌트 로컬 애플리케이션 글로벌
데이터 공유 Props drilling 또는 Context 필요 어느 컴포넌트에서 직접 접근
적합한 사용 사례 룰 상태 UI 상태, 작은 앱 복잡한 앱, 전역 상태, 다수구 툴

개발 경험

설정 복잡도 매우 간단 복잡한 초기 설정
학습 곡선 낮음 높음
보일러플레이트 최소 많음
개발 도구 React DevTools Redux DevTools (시간 여행 등)

성능

리렌더링 상태 변경시 해당 컴포넌트만 실력한 구독으로 최적화 가능
메모리 사용 컴포넌트와 함께 해제 앱 생명주기 동안 유지
상태 지속성 컴포넌트는 언마운트시 소실 앱 전체에서 지속

고급 기능

미들웨어 지원하지 않음 Redux Thunk, Saga, Observable 등
시간 여행 디버깅 불가능 Redux DevTools 가능
상태 영속화 직접 구현 필요 redux-persist 등 라이브러리
핫 리로딩 제한적 완전 지원

 

사용 권장 사항

useReducer 사용하는 경우

  • 단일 컴포넌트의 복잡한 상태 관리
  • 빠른 프로토타이핑
  • 작은 규모의 애플리케이션
  • Redux 없이 reducer 패턴 사용하고 싶을 때
  • 번들 크기를 최소화하고 싶을 때

Redux 사용하는 경우

  • 복잡한 전역 상태 관리가 필요할 때
  • 다른 컴포넌트가 같은 상태를 공유할 때
  • 시간 여행 디버깅이 필요할 때
  • 상태 변경을 예측 가능하게 관리하고 싶을 때
  • 대규모 팀 개발 프로젝트

 

 

 

 

 

 

 

 

코딩애플 채널에서 쉽게 설명한 영상... 참고

https://www.youtube.com/watch?v=QZcYz2NrDIs

 

 

반응형