본문 바로가기
개발 공부 시리즈/Redux-ToolKit

[React] Redux-Toolkit TypeScript Quick Start

by 그레이웅 2022. 10. 20. 15:43
반응형

.

Redux-Toolkit TypeScript  Quick Start

https://ko.redux.js.org/tutorials/typescript-quick-start

 

TypeScript Quick Start | Redux

- How to set up and use Redux Toolkit and React-Redux with TypeScript

ko.redux.js.org

이번 포스팅에서는 Redux-Toolkit TypeScript Quick Start 공식문서를 보며 공부해 보겠다.

리덕스 툴킷에서 타입 스크립트를 간결하게 사용하는 예제를 따라 하면서 구현할 것이다.

 

Redux-Toolkit 설치 방법을 이전 포스팅에서 정리해놓았다.

 

2022.10.03 - [개발 공부 시리즈/Redux-ToolKit] - [React] Redux-Toolkit 초기설치

 

 

1. RTK TS 설치하기

 

RTK의 타입 스크립트 설치 방법은 다음과 같이 개별로 설치할 수 있지만

 

npm install @types/react-redux

 

타입스크립트 템플릿으로도 다운로드가 가능하다.

// Redux + TypeScript template
// 가운데 rtk-ts는 자신이 생성할 프로젝트 명이다.
npx create-react-app rtk-ts --template redux-typescript

나는 해당 디렉터리에 글로벌로 설치된 cra가 버전이 안 맞아서 npx를 빼고 설치를 하였다.

 

create-react-app rtk-ts --template redux-typescript

 

설치를 하면 다음과 같이 redux 타입 스크립트 템플릿에 맞게 설치가 된다.

 

 

 

 

 

2. RTK TS 프로젝트 설정 보기

 

RootState 및 Dispatch type 정의

 

- app/store.ts

import { configureStore } from '@reduxjs/toolkit'
// ...

const store = configureStore({
  reducer: {
    posts: postsReducer,
    comments: commentsReducer,
    users: usersReducer
  }
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

app 폴더에 store.ts를 보면 

 

TypeScript에서 기본적인 설정은 똑같지만

export 하는 부분에서 두 가지의 코드가 추가된 것을 볼 수 있다.

RootState를 지정하여 Return Type을 추출하는 것이다. (RootState로 이름을 지정한 것은 state와 혼동되지 않기 위해서이다.) 

AppDispatch의 코드도 dispatch의 타입을 얻기 위해 작성된 코드로(dispach와 혼동되지 않기 위해서 AppDispatch로 작성되었다.)

 

store에서 이러한 타입을 추출하면 slice나 미들웨어 설정을 할 때 업데이트가 올바르게 된다.

 

 

hook의 정의

- app/hooks.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

 

추가로 RTK-ts는 hooks.ts 파일을 사용하는데, 바로 RootState 및 AppDispatch의 타입을 가져올 수 있지만, 훅을 사용하는 것이 더 좋다.

 

훅을 사용하면 다음과 같은 장점이 있는데

1. useSelector를 사용할 때 (state : RootState)를 매번 입력해 줄 필요가 없다.

2. useDispatch를 사용할 때, 기본적인 Dispatch는 thunks에 대해 알지 못한다. thunk를 dispach 하려면 스토어에서 thunk 미들웨어 타입을 포함하는 AppDispatch 타입을 정의하고, useDispatch와 함께 써야 된다.

이렇게 훅으로 useDispatch를 추가하면, 필요한 곳에서 AppDispatch를 가져올 수 있다.

 

별도로 app/hook.ts라는 파일이 존재해야 잠재적인 순환 import 의존성 문제에서 벗어날 수 있다.

 

 

Slice와 Action Type의 정의

 

- features/counter/counterSlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../../app/store'

// Define a type for the slice state
interface CounterState {
  value: number
}

// Define the initial state using that type
const initialState: CounterState = {
  value: 0
}

export const counterSlice = createSlice({
  name: 'counter',
  // `createSlice` will infer the state type from the `initialState` argument
  initialState,
  reducers: {
    increment: state => {
      state.value += 1
    },
    decrement: state => {
      state.value -= 1
    },
    // Use the PayloadAction type to declare the contents of `action.payload`
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload
    }
  }
})

export const { increment, decrement, incrementByAmount } = counterSlice.actions

// Other code such as selectors can use the imported `RootState` type
export const selectCount = (state: RootState) => state.counter.value

export default counterSlice.reducer

 

각 Slice의 파일의 initState는 생성될 때 type을 정의하여 올바른 타입을 추론할 수 있도록 구현해야 한다.

모든 action들은 PayloadAction<T> 제네릭을 사용하여 정의해야 한다.

 

생성된 action creator는 PayloadAction <T>의 타입에 따라 payload의 인자로 제공되어 reducer에 넘겨주기 위해 올바른 타입이 필요하다.

예제에서는 인자로 숫자가 필요하기 때문에 <number>로 입력되었다.

 

훅 컴포넌트 사용하기

- feactures/counter/Counter.tsx

import React from 'react'

import { useAppSelector, useAppDispatch } from 'app/hooks'

import { decrement, increment } from './counterSlice'

export function Counter() {
  // The `state` arg is correctly typed as `RootState` already
  const count = useAppSelector(state => state.counter.value)
  const dispatch = useAppDispatch()

  // omit rendering logic
}

 

컴포넌트에서는 아까 미리 app/hooks.ts에 타입을 추출할 수 있는 훅을 정의해 놓은 파일을 가져와서 사용한다.

 


이와 같이 RTK환경에서 Typescript를 사용하는 방법을 알아보았다.

아직 이해도가 부족해서 직접 구현하고, 공부를 해보며 추가할 내용이 있으면 추가해야겠다.

 

반응형

댓글