본문 바로가기

Front-End/React

React #24 (Redux - 리듀서 활용)

반응형

 

(Ch05_2 의 내용을 기반으로 하고 있습니다.)

https://github.com/2jisu/do-it-react-with-ts/tree/main/Chapter05/02

 

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

 

 

Redux의 리듀서를 활용해서 몇 가지 만들어 보는 걸로 하기.

 

 

 

src/store 안에 파일들 사전 세팅

 

(store 안의 파일들 종류와 기능 다시 한 번 살펴 보기)

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

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
}

 

AppState.ts

import * as Clock from './clock'
import * as Counter from './counter'
import * as R from './remoteUser'
import * as Cards from './cards'

export type AppState = {
    clock: Clock.State
    counter: Counter.State
    remoteUser: R.State
    cards: Cards.State
}

 

rootReducer.ts

import { combineReducers } from "redux";
import * as Clock from './clock'
import * as Counter from './counter'
import * as R from './remoteUser'
import * as Cards from './cards'


export const rootReducer = combineReducers({
        clock: Clock.reducer,
        counter: Counter.reducer,
        remoteUser: R.reducer,
        cards: Cards.reducer
})

 

index.ts

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

 

 

 

 

 

1. Clock

※ src/store 안에 clock 디렉토리를 만듭니다.

 

src/store/clock

더보기

types.ts

import type { Action } from "redux";

export type State = string

export type SetClockAction = Action<'@clock/setClock'> & {
    payload: State
}

export type Actions = SetClockAction

 

actions.ts

import type * as T from './types'

export const setClock = (payload: T.State): T.SetClockAction => ({
    type: '@clock/setClock',
    payload
})

 

reducers.ts

import * as T from './types'

const initialState: T.State = new Date().toISOString()


export const reducer = (state: T.State = initialState, action: T.Actions) => {
    switch (action.type) {
        case '@clock/setClock':
            return action.payload
    }
    return state;
}

 

index.ts

export * from './types'
export * from './actions'
export * from './reducers'



 

src/App.tsx

import { Provider as ReduxProvider } from 'react-redux'
import { useStore } from './store'
import ClockTest from './pages/ClockTest'


export default function App() {
  
  const store = useStore()

  return (
    <ReduxProvider store={store}>    
      <ClockTest />
    </ReduxProvider>
  )
}



 

 

 

 

2. Counter

※ src/store 안에 counter 디렉토리를 만듭니다.

 

src/store/counter

더보기

types.ts

import type { Action } from "redux";

export type State = number

export type SetCounterAction = Action<'@counter/setCounter'> & {
    payload: State
}

export type Actions = SetCounterAction

 

actions.ts

import type * as T from './types'

export const setCounter = (payload: T.State): T.SetCounterAction => ({
    type: '@counter/setCounter',
    payload
})

export const increaseCounter = () => setCounter(1)
export const decreaseCounter = () => setCounter(-1)

 

reducers.ts

import * as T from './types'

const initialState: T.State = 0


export const reducer = (state: T.State = initialState, action: T.Actions) => {
    
    switch (action.type) {
        case '@counter/setCounter':
            return state + action.payload   
    }
    return state;
}

 

index.ts

export * from './types'
export * from './actions'
export * from './reducers'

 

 

 

src/App.tsx

import { Provider as ReduxProvider } from 'react-redux'
import { useStore } from './store'
import ClockTest from './pages/ClockTest'
import CounterTest from './pages/CounterTest'


export default function App() {
  
  const store = useStore()

  return (
    <ReduxProvider store={store}>
      <CounterTest />
      <ClockTest />
    </ReduxProvider>
  )
}

 

 

 

 

 

 

 

 

반응형