一 React-Redux的应用
1.学习文档
- 英文文档: Redux - A predictable state container for JavaScript apps. | Redux
- 中文文档: Redux 中文官网 - JavaScript 应用的状态容器,提供可预测的状态管理。 | Redux 中文官网
- Github: GitHub - reduxjs/redux: Predictable state container for JavaScript apps
2.Redux的需求
- 状态的集中管理
- 任意页面与组件之间的数据传递
- 状态管理的可预测
- 数据的本地化缓存提升性能
说明:
随着对JavaScript单页应用程序的要求变得越来越复杂,我们的代码必须比以前更多地处理状态。此状态可以包括服务器响应和缓存数据,以及本地创建的尚未保存到服务器的数据。 UI状态的复杂性也在增加,因为我们需要管理活动路线,选定标签,旋钮,分页控件等。 管理这个不断变化的状态是困难的。
如果一个模型可以更新另一个模型,那么一个视图可以更新一个模型,该模型会更新另一个模型,而这又可能导致另一个视图更新。在某种程度上,您不再理解您的应用程序会发生什么情况,因为您已经失去了对其状态的何时,为何和如何的控制。
当系统不透明且不确定时,很难重现错误或添加新功能。 好像这还不够糟糕,请考虑新的要求在前端产品开发中变得常见。作为开发人员,我们需要处理乐观的更新,服务器端渲染,在执行路由转换之前获取数据等等。
我们发现自己试图去处理一个我们以前从来没有处理过的复杂问题,而且我们不可避免地提出这个问题:是放弃的时候了吗?答案是不。
这种复杂性很难处理,因为我们正在混合两个对人类头脑非常难以推理的概念:突变和异步性。我把它们叫做曼托斯和可乐。两者在分离方面都很出色,但它们一起造成一团糟。像React这样的库试图通过去除异步和直接DOM操作来解决视图层中的这个问题。但是,管理数据的状态由您决定。这是Redux进入的地方。
3.什么是Redux
- redux是一个独立专门用于做状态管理的JS库(不是react插件库)
- 它可以用在react、angular、vue等项目中,但基本与react配合使用
- 作用:集中式管理react应用中多个组件共享的状态
4.什么情况下需要使用redux
- 总体原则: 大型项目状态管理复杂才用
- 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
二、最新React-Redux 的流程
安装Redux Toolkit
# NPM
npm install @reduxjs/toolkit
# Yarn
yarn add @reduxjs/toolkit
创建一个 React Redux 应用
官方推荐的使用 React 和 Redux 创建新应用的方式是使用官方 Redux+JS 模版或Redux+TS 模板,它基于Create React App,利用了Redux Toolkit和 Redux 与 React 组件的集成.
# Redux + Plain JS template
npx create-react-app my-app --template redux
# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript
Redux 核心库
Redux 核心库同样有 NPM 软件包,可与模块捆绑器或 Node 应用程序一起使用,安装方式如下:
# NPM
npm install redux
# Yarn
yarn add redux
基础示例
应用的整体全局状态以对象树的方式存放于单个store。 唯一改变状态树(state tree)的方法是创建action,一个描述发生了什么的对象,并将其dispatch给 store。 要指定状态树如何响应 action 来进行更新,你可以编写纯reducer函数,这些函数根据旧 state 和 action 来计算新 state。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Redux Toolkit 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
三、使用教程
安装Redux Toolkit和React-Redux
添加 Redux Toolkit 和 React-Redux 依赖包到你的项目中:
创建 Redux Store
创建src/app/store.js
文件。从 Redux Toolkit 引入configureStore
API。我们从创建一个空的 Redux store 开始,并且导出它:
app/store.js
1 2 3 4 |
|
npm install @reduxjs/toolkit react-redux
上面代码创建了 Redux store ,并且自动配置了 Redux DevTools 扩展 ,这样你就可以在开发时调试 store。
为React提供Redux Store
创建 store 后,便可以在 React 组件中使用它。 在 src/index.js 中引入我们刚刚创建的 store , 通过 React-Redux 的<Provider>
将<App>
包裹起来,并将 store 作为 prop 传入。
index.js
1 2 3 4 5 6 7 8 9 10 11 12 |
|
创建Redux State Slice
创建src/features/counter/counterSlice.js
文件。在该文件中从 Redux Toolkit 引入createSlice
API。
创建 slice 需要一个字符串名称来标识切片、一个初始 state 以及一个或多个定义了该如何更新 state 的 reducer 函数。slice 创建后 ,我们可以导出 slice 中生成的 Redux action creators 和 reducer 函数。
Redux 要求我们通过创建数据副本和更新数据副本,来实现不可变地写入所有状态更新。不过 Redux ToolkitcreateSlice
和createReducer
在内部使用 Immer 允许我们编写“可变”的更新逻辑,变成正确的不可变更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
将Slice Reducers添加到Store 中
下一步,我们需要从计数切片中引入 reducer 函数,并将它添加到我们的 store 中。通过在 reducer 参数中定义一个字段,我们告诉 store 使用这个 slice reducer 函数来处理对该状态的所有更新。
app/store.js
1 2 3 4 5 6 7 |
|
在React组件中使用Redux状态和操作
现在我们可以使用 React-Redux 钩子让 React 组件与 Redux store 交互。我们可以使用useSelector
从 store 中读取数据,使用useDispatch
dispatch actions。创建包含<Counter>
组件的src/features/counter/Counter.js
文件,然后将该组件导入App.js
并在<App>
中渲染它。
features/counter/Counter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
现在,每当你点击”递增“和“递减”按钮。
- 会 dispatch 对应的 Redux action 到 store
- 在计数器切片对应的 reducer 中将看到 action 并更新其状态
<Counter>
组件将从 store 中看到新的状态,并使用新数据重新渲染组件
你学到了什么
这是关于如何通过 React 设置和使用 Redux Toolkit 的简要概述。 回顾细节:
总结
使用configureStore
创建 Redux store
configureStore
接受reducer
函数作为命名参数configureStore
使用的好用的默认设置自动设置 store
为 React 应用程序组件提供 Redux store
- 使用 React-Redux
<Provider>
组件包裹你的<App />
- 传递 Redux store 如
<Provider store={store}>
使用createSlice
创建 Redux "slice" reducer
- 使用字符串名称、初始状态和命名的 reducer 函数调用“createSlice”
- Reducer 函数可以使用 Immer 来“改变”状态
- 导出生成的 slice reducer 和 action creators
在 React 组件中使用 React-ReduxuseSelector/useDispatch
钩子
- 使用
useSelector
钩子从 store 中读取数据 - 使用
useDispatch
钩子获取dispatch
函数,并根据需要 dispatch actions