이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
Redux Toolkit TypeScript 빠른 시작
- TypeScript와 함께 Redux Toolkit 및 React-Redux를 설정하고 사용하는 방법
- React 훅에 대한 지식
- Redux 용어 및 개념 이해
- TypeScript 구문 및 개념 이해
소개
Redux Toolkit TypeScript 빠른 시작 튜토리얼에 오신 것을 환영합니다! 이 튜토리얼에서는 TypeScript를 Redux Toolkit 및 React-Redux와 함께 사용하는 방법을 간략히 설명합니다.
이 페이지는 TypeScript 관련 설정 방법에 초점을 맞춥니다. Redux가 무엇인지, 어떻게 작동하는지에 대한 설명과 Redux Toolkit 사용법의 전체 예시는 "튜토리얼 인덱스" 페이지의 링크를 참조하세요.
Redux Toolkit은 이미 TypeScript로 작성되어 있어 TS 타입 정의가 내장되어 있습니다.
React Redux 또한 버전 8부터 TypeScript로 작성되었으며 자체 타입 정의를 포함하고 있습니다.
Create-React-App용 Redux+TS 템플릿에는 이러한 패턴이 미리 구성된 작업 예제가 포함되어 있습니다.
프로젝트 설정
Root State 및 Dispatch 타입 정의
Redux Toolkit의 configureStore API는 추가 타이핑이 필요하지 않습니다. 그러나 참조할 수 있도록 RootState 타입과 Dispatch 타입을 추출해야 합니다. 이러한 타입을 스토어 자체에서 추론하면 상태 슬라이스를 추가하거나 미들웨어 설정을 수정할 때 정확히 업데이트됩니다.
해당 항목들은 타입이므로 app/store.ts와 같은 스토어 설정 파일에서 직접 내보내고 다른 파일로 직접 가져오는 것이 안전합니다.
import { configureStore } from '@reduxjs/toolkit'
// ...
export const store = configureStore({
reducer: {
posts: postsReducer,
comments: commentsReducer,
users: usersReducer
}
})
// Infer the `RootState`, `AppDispatch`, and `AppStore` 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
export type AppStore = typeof store
타이핑된 훅 정의
각 컴포넌트에 RootState 및 AppDispatch 타입을 가져오는 것도 가능하지만, 애플리케이션에서 사용할 타이핑된 useDispatch 및 useSelector 훅 버전을 만드는 것이 더 좋습니다. 이는 다음과 같은 이유로 중요합니다:
-
useSelector의 경우 매번(state: RootState)를 입력할 필요가 없어집니다 -
useDispatch의 경우 기본Dispatch타입은 썽크(thunk)를 인식하지 못합니다. 썽크를 올바르게 디스패치하려면 썽크 미들웨어 타입을 포함하는 스토어의 특수한AppDispatch타입을 사용하고 이를useDispatch와 함께 사용해야 합니다. 미리 타이핑된useDispatch훅을 추가하면 필요한 곳에AppDispatch를 가져오는 것을 잊지 않도록 방지합니다.
이들은 실제 변수이지 타입이 아니므로 스토어 설정 파일이 아닌 app/hooks.ts와 같은 별도 파일에 정의하는 것이 중요합니다. 이렇게 하면 훅을 사용해야 하는 모든 컴포넌트 파일로 가져올 수 있으며 잠재적인 순환 가져오기 종속성 문제를 피할 수 있습니다.
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
애플리케이션 사용
슬라이스 상태 및 액션 타입 정의
각 슬라이스 파일은 초기 상태 값에 대한 타입을 정의해야 하므로 createSlice가 각 케이스 리듀서에서 state의 타입을 올바르게 추론할 수 있습니다.
생성된 모든 액션은 Redux Toolkit의 PayloadAction<T> 타입을 사용하여 정의해야 합니다. 이 타입은 제네릭 인자로 action.payload 필드의 타입을 받습니다.
여기서 스토어 파일에서 RootState 타입을 안전하게 가져올 수 있습니다. 순환 가져오기이지만 TypeScript 컴파일러는 타입에 대해 이를 올바르게 처리할 수 있습니다. 셀렉터 함수 작성과 같은 사용 사례에 필요할 수 있습니다.
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../../app/store'
// Define a type for the slice state
export 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
생성된 액션 생성자는 리듀서에 제공한 PayloadAction<T> 타입을 기반으로 payload 인수를 올바르게 수락하도록 타이핑됩니다. 예를 들어 incrementByAmount는 인수로 number를 요구합니다.
경우에 따라 TypeScript가 초기 상태의 타입을 불필요하게 좁게 추론할 수 있습니다. 이럴 때는 변수의 타입을 선언하는 대신 as를 사용하여 초기 상태를 타입 캐스팅하면 해결할 수 있습니다:
// Workaround: cast state instead of declaring variable type
const initialState = {
value: 0
} as CounterState
컴포넌트에서 Typed Hooks 사용하기
컴포넌트 파일에서는 React-Redux의 표준 훅 대신 미리 타입이 지정된 훅을 가져와야 합니다.
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
}
전체 카운터 앱 예제
다음은 실행 가능한 CodeSandbox로 구현한 TypeScript 카운터 애플리케이션의 전체 예제입니다:
다음 단계
Redux Toolkit에 포함된 모든 주요 기능, 그것들이 해결하는 문제, 그리고 실제 애플리케이션을 구축하는 방법을 다루는 전체 "Redux Essentials" 튜토리얼을 진행해 보는 것을 권장합니다.
또한 Redux의 작동 방식, Redux Toolkit이 하는 일, 그리고 올바른 사용법을 완전히 이해할 수 있도록 "Redux Fundamentals" 튜토리얼을 읽어보는 것도 좋습니다.
마지막으로, TypeScript와 함께 Redux Toolkit의 API를 사용하는 방법에 대한 자세한 내용은 "TypeScript 사용법" 페이지를 참고하세요.