Redux Toolkit TypeScript 快速入门
- 如何使用 TypeScript 设置和使用 Redux Toolkit 和 React-Redux
- 了解 React Hooks
- 了解 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 模板 带有一个已经配置好的这些模式的工作示例。
项目设置
定义根状态和调度类型
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` 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
定义类型化钩子
虽然可以将 RootState
和 AppDispatch
类型导入到每个组件中,但最好为您的应用程序中的使用创建 useDispatch
和 useSelector
钩子的类型化版本。这对于几个原因很重要
- 对于
useSelector
,它可以节省您每次都键入(state: RootState)
的需要 - 对于
useDispatch
,默认的Dispatch
类型不知道 thunk。为了正确地分派 thunk,您需要使用来自存储的特定自定义AppDispatch
类型,该类型包含 thunk 中间件类型,并将其与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
可以正确推断每个情况 reducer 中 state
的类型。
所有生成的 action 应该使用 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
生成的 action 创建者将被正确地类型化以接受一个 payload
参数,该参数基于您为 reducer 提供的 PayloadAction<T>
类型。例如,incrementByAmount
需要一个 number
作为其参数。
在某些情况下,TypeScript 可能会不必要地收紧初始状态的类型。如果发生这种情况,您可以通过使用 as
转换初始状态来解决它,而不是声明变量的类型
// Workaround: cast state instead of declaring variable type
const initialState = {
value: 0
} as CounterState
在组件中使用类型化钩子
在组件文件中,导入预类型化的钩子,而不是从 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
}
完整计数器应用程序示例
这是一个完整的 TS 计数器应用程序,作为运行的 CodeSandbox
下一步
我们建议您学习完整的“Redux Essentials”教程,该教程涵盖了 Redux Toolkit 中包含的所有关键部分,它们解决的问题以及如何使用它们构建现实世界的应用程序。
您可能还想阅读“Redux Fundamentals”教程,它将让您全面了解 Redux 的工作原理、Redux Toolkit 的作用以及如何正确使用它。
最后,请参阅“使用 TypeScript”页面,以获取有关如何将 Redux Toolkit 的 API 与 TypeScript 一起使用的详细信息。