Redux 入门
Redux 是一个用于可预测且可维护的全局状态管理的 JS 库。
它帮助您编写行为一致的应用程序,在不同的环境(客户端、服务器和原生)中运行,并且易于测试。最重要的是,它提供了极佳的开发体验,例如 实时代码编辑与时间旅行调试器相结合。
您可以将 Redux 与 React 或任何其他视图库一起使用。它很小(2kB,包括依赖项),但拥有庞大的附加组件生态系统。
Redux Toolkit 是我们官方推荐的编写 Redux 逻辑的方法。它围绕 Redux 核心进行包装,并包含我们认为构建 Redux 应用程序必不可少的包和函数。Redux Toolkit 内置了我们建议的最佳实践,简化了大多数 Redux 任务,防止常见错误,并使编写 Redux 应用程序变得更加容易。
RTK 包含有助于简化许多常见用例的实用程序,包括 商店设置、创建 reducer 和编写不可变更新逻辑,甚至 一次创建整个“切片”状态。
无论您是刚开始使用 Redux 设置第一个项目的新手,还是想要简化现有应用程序的经验丰富的用户,Redux Toolkit 都可以帮助您改进 Redux 代码。
安装
Redux Toolkit
Redux Toolkit 作为 NPM 上的包提供,可用于模块打包器或 Node 应用程序。
# NPM
npm install @reduxjs/toolkit
# Yarn
yarn add @reduxjs/toolkit
创建 React Redux 应用程序
使用 React 和 Redux 启动新应用程序的推荐方法是使用 我们官方的 Redux+TS 模板 for Vite,或者使用 Next 的 with-redux
模板 创建新的 Next.js 项目。
这两个模板都已为该构建工具正确配置了 Redux Toolkit 和 React-Redux,并附带一个小型示例应用程序,演示了如何使用 Redux Toolkit 的几个功能。
# Vite with our Redux+TS template
# (using the `degit` tool to clone and extract the template)
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
# Next.js using the `with-redux` template
npx create-next-app --example with-redux my-app
我们目前没有官方的 React Native 模板,但建议使用这些模板来创建标准的 React Native 应用程序和 Expo 应用程序。
- https://github.com/rahsheen/react-native-template-redux-typescript
- https://github.com/rahsheen/expo-template-redux-typescript
Redux 核心
Redux 核心库作为 NPM 上的包提供,可用于模块打包器或 Node 应用程序。
# NPM
npm install redux
# Yarn
yarn add redux
该包包含一个预编译的 ESM 构建,可以直接在浏览器中用作 <script type="module">
标签。
有关更多详细信息,请参阅 安装 页面。
基本示例
应用程序的整个全局状态存储在一个名为 store 的单个对象树中。更改状态树的唯一方法是创建一个 action(描述发生事件的对象)并将其 dispatch 到 store。为了指定状态如何响应 action 更新,您需要编写纯 reducer 函数,这些函数根据旧状态和 action 计算新状态。
Redux Toolkit 简化了编写 Redux 逻辑和设置 store 的过程。使用 Redux Toolkit,基本应用程序逻辑如下所示。
import { createSlice, configureStore } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})
export const { incremented, decremented } = counterSlice.actions
const store = configureStore({
reducer: counterSlice.reducer
})
// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))
// Still pass action objects to `dispatch`, but they're created for us
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}
您无需直接修改状态,而是使用名为 action 的普通对象指定要发生的修改。然后,您编写一个名为 reducer 的特殊函数来决定每个 action 如何转换整个应用程序的状态。
在典型的 Redux 应用程序中,只有一个 store 和一个根 reducer 函数。随着应用程序的增长,您将根 reducer 分割成更小的 reducer,这些 reducer 独立地操作状态树的不同部分。这与 React 应用程序中只有一个根组件但由许多小组件组成的方式完全相同。
对于一个计数器应用程序来说,这种架构可能看起来很复杂,但这种模式的美妙之处在于它可以很好地扩展到大型和复杂的应用程序。它还支持非常强大的开发者工具,因为可以追踪每个突变到导致它的操作。你可以记录用户会话并通过重播每个操作来重现它们。
Redux Toolkit 允许我们编写更短的逻辑,更容易阅读,同时仍然遵循相同的 Redux 行为和数据流。
传统示例
为了比较,原始 Redux 传统语法(没有抽象)看起来像这样
import { createStore } from 'redux'
/**
* This is a reducer - a function that takes a current state value and an
* action object describing "what happened", and returns a new state value.
* A reducer's function signature is: (state, action) => newState
*
* The Redux state should contain only plain JS objects, arrays, and primitives.
* The root state value is usually an object. It's important that you should
* not mutate the state object, but return a new object if the state changes.
*
* You can use any conditional logic you want in a reducer. In this example,
* we use a switch statement, but it's not required.
*/
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}
// Create a Redux store holding the state of your app.
// Its API is { subscribe, dispatch, getState }.
let store = createStore(counterReducer)
// You can use subscribe() to update the UI in response to state changes.
// Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly.
// There may be additional use cases where it's helpful to subscribe as well.
store.subscribe(() => console.log(store.getState()))
// The only way to mutate the internal state is to dispatch an action.
// The actions can be serialized, logged or stored and later replayed.
store.dispatch({ type: 'counter/incremented' })
// {value: 1}
store.dispatch({ type: 'counter/incremented' })
// {value: 2}
store.dispatch({ type: 'counter/decremented' })
// {value: 1}
学习 Redux
我们提供各种资源来帮助你学习 Redux。
Redux Essentials 教程
Redux Essentials 教程 是一个“自上而下”的教程,它使用我们最新的推荐 API 和最佳实践来教授“如何正确使用 Redux”。我们建议从这里开始。
Redux 基础教程
Redux 基础教程 是一个“自下而上”的教程,它从第一原理开始教授“Redux 如何工作”,没有任何抽象,以及为什么存在标准 Redux 使用模式。
学习现代 Redux 直播
Redux 维护者 Mark Erikson 出现在“Learn with Jason”节目中,解释了我们今天推荐如何使用 Redux。该节目包括一个实时编码的示例应用程序,展示了如何使用 Redux Toolkit 和 React-Redux hooks 与 TypeScript,以及新的 RTK Query 数据获取 API。
查看“学习现代 Redux”节目笔记页面,获取文字记录和示例应用程序源代码的链接。
其他教程
- Redux 存储库包含几个示例项目,演示了如何使用 Redux 的各个方面。几乎所有示例都有一个对应的 CodeSandbox 沙箱。这是一个交互式的代码版本,你可以在线玩。在示例页面中查看完整的示例列表。
- Redux 创建者 Dan Abramov 在 Egghead.io 上的免费“Redux 入门”视频系列 和使用惯用 Redux 构建 React 应用程序 视频课程。
- Redux 维护者 Mark Erikson 的 **"Redux Fundamentals" 会议演讲** 和 "Redux Fundamentals" 工作坊幻灯片
- Dave Ceddia 的文章 面向初学者的完整 React Redux 教程
其他资源
- **Redux 常见问题解答** 回答了关于如何使用 Redux 的许多常见问题,而 **"使用 Redux" 文档部分** 包含了关于处理派生数据、测试、构建 reducer 逻辑和减少样板代码的信息。
- Redux 维护者 Mark Erikson 的 **"实用 Redux" 教程系列** 演示了使用 React 和 Redux 的真实世界中级和高级技术(也以 **Educative.io 上的交互式课程** 的形式提供)。
- **React/Redux 链接列表** 对使用 reducer 和 selector、管理副作用、Redux 架构和最佳实践 等方面的文章进行了分类。
- 我们的社区创建了数千个与 Redux 相关的库、插件和工具。**"生态系统" 文档页面** 列出了我们的推荐,并且在 **Redux 插件目录** 中提供了完整的列表。
帮助与讨论
**#redux 频道** 是 **Reactiflux Discord 社区** 的官方资源,用于回答与学习和使用 Redux 相关的所有问题。Reactiflux 是一个很棒的地方,可以在这里闲逛、提问和学习 - 快来加入我们吧!
您也可以在 Stack Overflow 上使用 **#redux 标签** 提问。
如果您有错误报告或需要提供其他反馈,请 在 Github 仓库上提交问题
你应该使用 Redux 吗?
Redux 是一个组织状态的宝贵工具,但你也要考虑它是否适合你的情况。不要仅仅因为有人说你应该使用 Redux 就使用它 - 花些时间了解使用它的潜在好处和权衡。
以下是一些关于何时使用 Redux 的建议
- 你有合理数量的数据随着时间的推移而改变
- 你需要一个单一的事实来源来管理你的状态
- 你发现将所有状态保存在顶级组件中不再足够了
有关 Redux 如何使用的更多想法,请参阅