跳至主要內容

Redux Toolkit TypeScript 快速入門

您將學到什麼
  • 如何使用 TypeScript 設定並使用 Redux Toolkit 和 React-Redux
先備條件

簡介

歡迎使用 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 範本附有已設定好這些模式的實際範例。

專案設定

定義根狀態和傳送類型

Redux Toolkit 的 configureStore API 不需要任何額外的型別。不過,您會想要擷取 RootState 型別和 Dispatch 型別,以便在需要時參照它們。從儲存體本身推論這些型別表示,當您新增更多狀態區段或修改中間件設定時,它們會正確更新。

由於這些是型別,因此可以安全地從儲存體設定檔(例如 app/store.ts)直接匯出它們,並直接匯入其他檔案。

app/store.ts
import { configureStore } from '@reduxjs/toolkit'
// ...

export 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

定義型別掛鉤

雖然可以將 RootStateAppDispatch 型別匯入每個元件,但最好為應用程式中的 useDispatchuseSelector 掛鉤建立型別版本。這有幾個原因很重要

  • 對於 useSelector,它讓您不必每次都輸入 (state: RootState)
  • 對於 useDispatch,預設的 Dispatch 型別不知道 thunk。為了正確傳送 thunk,您需要使用儲存體中包含 thunk 中間件型別的特定自訂 AppDispatch 型別,並將其與 useDispatch 搭配使用。新增預先型別化的 useDispatch 掛鉤可讓您不會忘記在需要的地方匯入 AppDispatch

由於這些是實際變數,而非型別,因此務必在 app/hooks.ts 等獨立檔案中定義它們,而不是儲存體設定檔。這讓您可以將它們匯入需要使用掛鉤的任何元件檔案,並避免潛在的循環匯入依賴關係問題。

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 編譯器可以正確處理類型。這對於撰寫選擇器函式等使用案例可能是必要的。

features/counter/counterSlice.ts
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

產生的動作建立器將正確設定為接受 payload 引數,其根據你為簡化器提供的 PayloadAction<T> 類型。例如,incrementByAmount 需要 number 作為其引數。

在某些情況下,TypeScript 可能會不必要地收緊初始狀態的類型。如果發生這種情況,你可以使用 as 轉換初始狀態,而不是宣告變數的類型來解決此問題

// Workaround: cast state instead of declaring variable type
const initialState = {
value: 0
} as CounterState

在元件中使用型別化掛勾

在元件檔案中,匯入預先設定型別的掛勾,而不是 React-Redux 中的標準掛勾。

features/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
}

完整的計數器應用程式範例

以下是完整的 TS 計數器應用程式,作為執行中的 CodeSandbox

接下來是什麼?

我們建議瀏覽完整的「Redux Essentials」教學課程,其中涵蓋 Redux Toolkit 中包含的所有關鍵部分、它們解決的問題以及如何使用它們來建置真實世界的應用程式。

你可能還想閱讀「Redux Fundamentals」教學課程,這將讓你全面了解 Redux 的運作方式、Redux Toolkit 的功能以及如何正確使用它。

最後,請參閱「與 TypeScript 搭配使用」頁面,以取得有關如何將 Redux Toolkit 的 API 與 TypeScript 搭配使用的詳細資訊。