什么是 Redux Toolkit?
Redux Toolkit(简称"RTK")是我们官方推荐的编写Redux逻辑的方法。@reduxjs/toolkit
包装了核心的redux
包,并包含我们认为在构建Redux应用程序时必不可少的 API 方法和常见依赖项。Redux Toolkit 内置了我们建议的最佳实践,简化了大多数 Redux 任务,预防了常见错误,并使编写 Redux 应用程序变得更容易。
如果你今天正在编写任何Redux逻辑,那么你应该使用 Redux Toolkit 来编写该代码!
RTK 包括一些实用工具,可以简化许多常见用例,包括存储设置、创建 reducer 和编写不可变更新逻辑,甚至一次性创建整个状态的“slices”。
无论你是一个全新的 Redux 用户正在设置你的第一个项目,还是一个有经验的用户想要简化现有的应用程序,Redux Toolkit都可以帮助你改进Redux代码。
请查看以下页面,了解如何使用 Redux Toolkit 实现“现代 Redux”:
- “Redux基础”教程,教授如何使用Redux Toolkit为真实世界应用程序编写“正确的方式”的Redux逻辑。
- Redux基础,第8部分:使用 Redux Toolkit 的现代 Redux,展示了如何将之前教程中低级别示例转换为现 代Redux Toolkit等效版本。
- 使用 Redux:迁移到现代 Redux,介绍了如何将不同类型的旧版 Redux 逻辑迁移到现代 Redux 等效版本。
Redux Toolkit 与 Redux 核心有何不同
什么是“Redux”?
首先要问的是,“Redux”是什么?
Redux实际上是:
- 包含“全局”状态的单一存储
- 当应用程序发生某些事件时,向存储分派普通对象 action
- 纯粹的 reducer 函数查看这些 action 并返回不可变的更新状态
虽然不是必需的,你的Redux代码通常还包括:
- 生成这些 action 对象的 action 创建器
- 用于启用副作用的中间件
- 包含同步或异步具有副作用逻辑的Thunk函数
- 正常化状态以启用按ID查找项目
- 使用 Reselect 库优化派生数据的记忆选择器函数
- Redux DevTools 扩展,用于查看你的操作历史和状态更改
- 用于 action 、状态和其他函数的 TypeScript 类型
此外,Redux 通常与 React-Redux 库一起使用,以使你的 React 组件能够与 Redux 存储进行通信。
Redux 核心有什么作用?
Redux 核心是一个非常小而故意不强调观点的库。它提供了一些小的API原语:
createStore
用于实际创建Redux存储combineReducers
用于将多个切片 reducer 组合成单个较大的 reducerapplyMiddleware
用于将多个中间件组合成存储增强器compose
用于将多个存储增强器组合成单个存储增强器
除此之外,你的应用程序中所有其他与Redux相关的逻辑都必须完全由你编写。
好消息是这意味着 Redux 可以 以许多不同的方式使用。坏消息是没有任何助手使你的任何代码更容易编写。
例如,reducer 函数只是一个函数。在 Redux Toolkit 之前,你通常会使用 switch
语句和手动更新来编写该 reducer。你还可能会手动编写 action 创建器和 action 类型常量:
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from '../features/todos/todosSlice'
import filtersReducer from '../features/filters/filtersSlice'
export const store = configureStore({
reducer: {
todos: todosReducer,
filters: filtersReducer
}
})
这段代码中没有任何依赖于 redux
核心库的 API。但是,这是很多代码需要编写的。不可变更新需要大量手动编写的对象扩展和数组操作,很容易犯错误并在过程中意外更改状态(这始终是 Redux 错误的#1原因!)。此外,尽管不是严格要求,但通常会将一个功能的代码分散在多个文件中,例如 actions/todos.js
、constants/todos.js
和 reducers/todos.js
。
此外,存储设置通常需要一系列步骤来添加常用中间件,例如 thunks 和启用 Redux DevTools 扩展支持,尽管这些都是几乎每个Redux 应用程序中使用的标准工具。
Redux Toolkit 是做什么的?
尽管这些原本是在 Redux 文档中展示的模式,但不幸的是,它们需要大量冗长和重复的代码。这大部分模板代码在使用 Redux 时并非必要。此外,这些模板代码还增加了出错的机会。
我们特意创建了 Redux Toolkit,以消除手写 Redux 逻辑中的“模板代码”,防止常见错误,并提供简化标准 Redux 任务的 API。
Redux Toolkit 从简化每个 Redux 应用程序中的最常见任务的两个关键 API 开始:
configureStore
通过单个函数调用设置了一个配置良好的 Redux 存储,包括合并 reducer、添加 thunk 中间件和设置 Redux DevTools 集成。它还比createStore
更容易配置,因为它接受了命名选项参数。createSlice
允许你编写使用 Immer 库 的 reducer,以启用使用“变异”JS 语法(例如state.value = 123
)来编写不可变更新,无需扩展。它还会自动生成每个 reducer 的 action 创建函数,并在内部基于 reducer 的名称生成 action 类型字符串。最后,它在 TypeScript 中表现出色。
这意味着编写的代码可以大大简化。例如,相同的 todos reducer 可以如下所示:
import { createSlice } from '@reduxjs/toolkit'
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
todoAdded(state, action) {
state.push({
id: action.payload.id,
text: action.payload.text,
completed: false
})
},
todoToggled(state, action) {
const todo = state.find(todo => todo.id === action.payload)
todo.completed = !todo.completed
}
}
})
export const { todoAdded, todoToggled } = todosSlice.actions
export default todosSlice.reducer
所有的 action 创建函数和 action 类型都是自动生成的,reducer 代码更短,更容易理解。每种情况下实际更新的内容也更加清晰。
使用 configureStore
,存储设置可以简化为:
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from '../features/todos/todosSlice'
import filtersReducer from '../features/filters/filtersSlice'
export const store = configureStore({
reducer: {
todos: todosReducer,
filters: filtersReducer
}
})
请注意,这个 configureStore
调用会自动执行你手动完成的所有常规设置工作:
- 切片 reducer 自动传递给
combineReducers()
redux-thunk
中间件会自动添加- 在开发模式下添加了中间件以捕获意外的变异
- Redux DevTools Extension 会自动设置
- 中间件和 DevTools 增强器被组合在一起并添加到存储中
与此同时,configureStore
提供了选项,以便用户可以修改所有这些默认行为(例如,在生产中关闭 thunks 并添加 sagas,或在生产中禁用 DevTools)。
此后,Redux Toolkit 还包括用于常见 Redux 任务的其他 API:
createAsyncThunk
:抽象了标准的“在异步请求之前/之后分派 action”的模式createEntityAdapter
:用于 CRUD 操作的规范化状态的预构建 reducer 和选择器createSelector
:标准 Reselect API 的重新导出,用于记忆选择器createListenerMiddleware
:用于响应分派的 action 运行逻辑的副作用中间件
最后,RTK 包还包括“RTK Query”,作为 Redux 应用程序的全数据获取和缓存解决方案的独立可选的 @reduxjs/toolkit/query
入口点。它允许你定义端点(REST、GraphQL 或任何异步函数),并生成完全管理数据获取、更新加载状态和缓存结果的 reducer 和中间件。它还会自动生成可在组件中使用的 React Hooks 来获取数据,如 const { data, isFetching} = useGetPokemonQuery('pikachu')
每个这些 API 都是完全可选的,并针对特定用例进行设计,你可以 挑选和选择哪些 API 实际在你的应用程序中使用。但是,强烈建议你使用这些任务来帮助。
请注意,Redux Toolkit 仍然是 “Redux”! 仍然存在一个存储,用于更新
的分派 action 对象,以及用于异步逻辑的 thunk 编写能力,管理规范化状态,使用 TypeScript 对代码进行类型化以及使用 DevTools 的能力。只是相同结果需要编写的代码量明显减少了!
为什么我们希望你使用 Redux Toolkit
作为 Redux 维护者,我们的观点是:
我们希望所有 Redux 用户都使用 Redux Toolkit 编写他们的 Redux 代码,因为它简化了你的代码,同时消除了许多常见的 Redux 错误和错误!
早期 Redux 模式的“模板代码”和复杂性从未是 Redux 的 必要部分。这些模式之所以存在,只是因为:
- 最初的“Flux 架构”使用了一些相同的方法
- 早期的 Redux 文档显示了一些 action 类型常量,以启用按类型将代码分成不同文件的方法
- JavaScript 默认是一种可变语言,编写不可变更新需要手动扩展对象和数组
- Redux 最初是在几周内构建的,有意设计为只有少数 API 原语
此外,Redux 社区采用了一些特定的方法,增加了额外的模板代码:
- 强调使用
redux-saga
中间件作为编写副作用的常用方法 - 坚持手写 Redux action 对象的 TS 类型,并创建联合类型以限制可以在类型级别分派的 action
多年来,我们看到了人们在实际中如何使用 Redux。我们看到社区为生成 action 类型和创建器、异步逻辑和副作用以及数据获取等任务编写了数百个附加库。我们还看到了一直为用户带来痛苦的问题,例如意外突变状态、编写几十行代码只是为了进行一个简单的状态更新,以及难以追踪代码库的工作方式。我们帮助了成千上万的用户,他们试图学习和使用 Redux,却在努力理解所有组件如何拼合在一起,对于概念的数量和额外代码的数量感到困惑。我们知道我们的用户面临什么问题。
我们特意设计了 Redux Toolkit 来解决这些问题!
- Redux Toolkit 将存储设置简化为单个清晰的函数调用,同时保留了在需要时完全配置存储选项的能力
- Redux Toolkit 消除了意外的突变,这一直是 Redux 错误的首要原因
- Redux Toolkit 消除了手动编写任何 action 创建函数或 action 类型的需要
- Redux Toolkit 消除了手动且容易出错的不可变更新逻辑的需要
- Redux Toolkit 可以轻松地在一个文件中编写 Redux 功能的代码,而不是将其分散到多个单独的文件中
- Redux Toolkit 提供了出色的 TypeScript 支持,API 设计旨在为你提供出色的类型安全性,并将你在代码中定义的类型数量最小化
- RTK Query 可以消除编写任何 thunk、reducer、 action 创建器或 Effect Hook 来管理获取数据和跟踪加载状态的需要
因此:
我们明确建议我们的用户应该使用 Redux Toolkit(@reduxjs/toolkit
包),而不应该在今天的任何新的 Redux 代码中使用传统的redux
核心包!
即使对于现有应用程序,我们也建议至少将 createStore
替换为 configureStore
,因为开发模式中间件还将帮助你捕获现有代码库中的意外突变和可串行化错误。我们还鼓励你将最常使用的 reducer(以及将来编写的任何 reducer)切换到 createSlice
- 代码将更短,更容易理解,而安全性的改进将为你节省时间和精力。
redux
核心包仍然有效,但今天我们认为它已经过时了。所有这些 API 也从 @reduxjs/toolkit
中重新导出,configureStore
可以像 createStore
一样完成一切,但具有更好的默认行为和可配置性。
了解较低级别的概念也是有用的,这样你就可以更好地理解 Redux Toolkit 为你做了什么。这就是为什么 “Redux 基础”教程显示了 Redux 如何工作,没有抽象。然而,它仅作为学习工具显示这些示例,并最后显示 Redux Toolkit 如何简化旧的手写 Redux 代码。
如果你仅使用 redux
核心包本身,你的代码将继续工作。但是,我们强烈建议你切换到 @reduxjs/toolkit
,并更新你的代码以使用 Redux Toolkit 的 API!
更多信息
有关更多详细信息,请参阅以下文档页面和博客文章
评论 (0)