使用方法
状态容器与数据流管理
三大原则
单一数据源;
状态不可变
纯函数修改状态
一般来说,在程序设计中,我们会不知不觉地设定一些简单的协议,来进行两个模块之间的通信。比如 A 模块传递给 B 模块一些信息,B 模块要根据不同的信息类型来执行不同的操作,我们会这么写:
这样设计,我们就不必为每一种操作都写一个函数,那么这里的 data 就是一种协议的体现,也就是相当于 redux 中的 action,action 是一种只有两个字段 type 和 payload 的结构体。显然,创建 action 结构的函数,就叫做 actionCreator。向 action 的消费方,也就是 B 模块,传递 action 的方法,即 notifyB,就是一种 dispatch 的简单示例。
reducer 的 initState 只有在 store 中不存在这个 state 的时候才会被用到。preloadState 顾名思义就是初始化 store 数据的,这样就不必在初始化 app 的时候手动执行多个 action 去 set 数据了,比如说从 server 拉取数据并初始化 store,这个参数就是一个很好用的方式。
export 导出对象的每个 key 就是 reducer 纯函数。合并 reducer 的 API 传入的参数就是
prop-type
那么一定有一个类似于 store. makeNewState 的方法吧?其实, Redux 生成一个全新的页面 状态数据对象进行了拆解,它规定: 当页面需要展现新的数据状态时 ,我们只 需要 dispatch (派 发〉一个 action(动作/事件)即可。这个 action 其实也是一个 JavaScript 就像页面状态数 据树这个 JavaScript 对象描述了整个页面的状态一样, action 则描述了这个动作单元变化的所有 信息。
使用 reducer 数来接收 action ,并执行页面状态数据树的变更。经 reducer 函数处理之 后, store.getState 方法就会返回新页面的数据状态。
reducer action 需要由开发者编写。 reducer 接收 以下两个参数 当前页面数据状态。 被派发 action 所以这个函数的处理可以抽象表达出来: (previousState, action) => newState
在纯函数内不能存在任何副作用,包括但不限于
调用系统 API Date.now() 或者 Math.random() 等方法。
发送 络请求。
在函数体内修改外部变量的值。
使用 console.log()输出信息
调用存在副作用的函数等。
我们想象 个很现实的场景 假如发现程序中存在一个 Bug ,页面需要展示数据 1,但是 错误地展示了数据 2, 在 Redux 架构下,整个修复思路就变得非常清晰 出现任何问题一定 因为组件接收了不正确的 state ,那么这个 state 生出自 reducer 。我们先来看产生这个错误 state 的 reducer 接收到的 action 内容是否正确,如果正确,则说明 action 准确表达了需要做出的 改变,那么很有可能就是 reducer 数的内部处理出现了错误。
store 就是一个 JavaScript 对象
dispatchAction :派发 action • subscribe 订阅页面数据状态,即 store state 的变化 • getState 获取当前页面状态数据树,即 store 中的 state • replaceReducer: 一般开发用不到,社区一些热更新或者代码分离技术中可 能会使用到
createStore 方法可以接收
• reducer 为开发者编 duc 函数,必需。 • preloadedState :页面状态数据树的初始状态,可选 • enhancer 强器,函数 型,可选 reducer 数必须存在, 就是说 当开发者 store 同时定义好 reducer 函数 用来告知 store 数据状态如 根据 action 进行变更
构造 action
action 描述了状态变更的信息, 是需要页面做出的的变化, 这是由开发者定义并借助于 store.dispatch 派发的 action 本质上也是 JavaScript 对象, 为了清楚 redux 规定 action 对象需要有一个 type 属性, 作为描述这个 action 的名称来唯一确定这个 action , 一般采用 JavaScript String 类型 另外, action 往往还需要携带一些数据信息, 这些数据信息的属性名没 有要求,同时这些数据信息中包含了这个 action 的基本内容。
使用 action creator
使用 dispatch 派发 action
action 描述了 种变化,并携带这种变化的数据信息 。真正执行这种变化并生成正确数据 状态的是 reducer 方法。
为了解决 action type 类型巨大, 我们引入了 combineReducers , 借助于它我们可以对 reducer 函数进行拆分, 最后在合并成为一个完整的 reducer . 它接受一个 JavaScript 对象类型的函数.
const finalReducer = combineReducers({data1, data2, data3})
这个参数定义了 页面数据状态中不同的数据部分与更新这些数据的 reducer 函数之间的映射关系, 并最终返回一个合并完整的 reducer 函数.
redux 完全可以独立于 react 而存在, 需要开发者预先定义 action 和 reducer 函数, 同时在恰当的时候派发 action, 即 dispatch(action), 通过 store.subscribe 注册每一次数据更新后的回调逻辑, 这种回调逻辑往往就是对页面的渲染.
共享是指一个变量、对象或者内存空间在多个共享的作用域中出现,或者一个对象的属性在多个作用域范围内被传递. 共享带来的问题是, 针对共享的数据,我们需要完全掌握其在所有作用域空间内的情况,以保证代码的正确性.
·基本数据类型,如 undefined null number boo le an string ·引用类型,如 Object Array Function
一般基本数据类型都保存在栈内存当中,引用类型都保存在堆内存当中。
对于 JavaScript, 因为其灵活性, 我们完全可以保证不变性. 下面主要分数组和对象两种情况
数组操作
(1)增加一项 可以考虑 concat 方法, 它不会对原有数组进行改动, 而是创建一个新的数组
(2) 删除一项 对于删除某一项的操作, splice 也不能满足需求, 该方法会改变原有数组的值. 我们应该使用 slice.
(3)更新一项
对象操作
(1) 更新一项
(2) 增加一项
(3)删除一项 Object.keys reduce 方法,对除 note 性以外的所有属性进行累加拷贝 。
(4) 面多深层的数据 我们只能进行手动分开所有层分别进行拷贝, 实现一种深拷贝
我们封装了了一个常用的深拷贝工具函数.
// 中间件被嵌入在从框架接收请求到产生响应过程之中
redux 本身提供了 applyMiddleware 方法来接入中间件. 在 enhancer 参数的位置接入中间件
redux 使用思路
确定所需的状态数据。
根据交互和业务需求 分析确定 action
根据不 action ,完成 reducer 函数的编写
根据 reducer 创建 store
订阅数据更新, 完成视图渲染。
react-redux
容器组件
所谓容器,实际上是指数据状态和逻辑的容器。它并不负责展示 ,而是只维护内部状态,进行数据分发和处理派发 action 因此,容器组件对 Redux 是感知的,可以使用 Redux API ,比如 dispatch
展示组件
与容器组件相反,展示组件只负责接收相应的数据,完成页面展示,它本身并不维护数据和状态 实际上 ,为了渲染页面,展示组件所需要的所有数据都由容器组件通过 props 层层传递下来
Connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) connect 的核心是将开发者定义的组件, 包装转换生成容器组件。所生成的容器组件能使用 Redux store 中的哪些数据,全由 connect 的参数来确定。
connect 函数的返回值是一个 WrappedComponent 组件。 connect 是典型的柯里化函数 ,它执 行两次,第一次是设置参数;第二次是接收一个正常的 presentational Component 组件,并在该 组件的基础上返回 个容器组件 WrappedComponent 。这其实是一种高阶组件的用法
connect 第一次执行时的两个参数. 第一个参数 mapStateToProps 是一个函数, 它由开发者设定吗, 这个函数一定要返回一个纯 JavaScript 对象. 第二个参数 mapDispatchtoprops 的作用是将 dispatch 作为 props 传递给 WrappedComponent 组件. 它可以是一个函数, 也可以是一个对象.
mapStat ToProps mapDispatchToProps 定义了展示组件需要用 到的 store 内容 。其 mapStateToProps 负责输入逻辑,就是将状态数据映射到展示组件的参数( props )上:后者负责 输出逻辑,即将用户对展示组件的操作映射成 action.
bindActionCreators 版本,它只不过就是一个 shortcut tool。因为 Action 必须被 dispatch 才能生效,而 Action 往往是由 ActionCreator 生成的。比如一个 ActionCreator:
那么我们在业务逻辑中的用法一定就是:
如果每次都是这样调用,那么这个 dispatch 就显得有些臃肿。对于业务最好就是直接调用:
那么显然,我们需要实现一层包装,把 ActionCreator 映射成 dispatch+ActionCreator 的组合:
function bindActionCreator(actionCreator, dispatch) { return function(...args) { dispatch(actionCreator(...args)); }; } 注意,上面是 bindActionCreator 不是 bindActionCreators。
如果有很多这样的映射,自然就成了 bindActionCreators 了
先创建 action actionCreactors = 在用 dispatch 调用 action;
每一个 dispatch 出的 action 会依次(按照中间件插入的顺序)经过每一个中间件的处理的。 thunkMiddleware 是用来处理异步 action 的,action 的类型为函数类型, 而 loggerMiddleware 只能处理普通的 plain object 类型的 action, 所以顺序上需要在 thunkMiddleware 之后,等 thunkMiddleware 将函数类型的 action 处理转换成 plain object 类型的 action,在发挥作用。
常用的中间件
Redux 的异步中间件(如 Redux Thunk、Redux Saga)的核心原理是通过 拦截 Action 并 扩展 dispatch
方法,使得 Redux 能够处理异步操作。以下是其工作原理的详细解析:
一、Redux 中间件的核心机制
1. 中间件的本质
中间件是一个高阶函数链,通过改造 store.dispatch
方法,在 Action 到达 Reducer 之前插入自定义逻辑。它的核心结构如下:
2. 中间件的执行流程
创建中间件链:通过
applyMiddleware
将多个中间件组合成一个链式结构。分发 Action:调用
dispatch(action)
时,Action 依次经过所有中间件处理。最终执行:最后一个中间件调用原始的
dispatch
,将 Action 传递给 Reducer。
二、异步中间件的实现原理(以 Redux Thunk 为例)
1. Redux Thunk 的作用
允许 Action Creator 返回一个 函数(而不仅是普通对象),该函数可以执行异步操作(如 API 请求、定时器)并在完成后分发真正的 Action。
2. Redux Thunk 的源码简析
3. 异步 Action 的处理流程
步骤解析:
dispatch(fetchData())
分发一个函数类型的 Action。Redux Thunk 中间件检测到 Action 是函数,执行该函数并传入
dispatch
和getState
。函数内部先分发同步 Action(如
FETCH_START
),然后执行异步操作(如fetch
)。异步操作完成后,再次调用
dispatch
分发结果 Action(如FETCH_SUCCESS
)。
三、其他异步中间件的原理对比
1. Redux Saga
原理:基于 Generator 函数和 ES6
yield
语法,监听特定的 Action,并执行复杂的异步流程(如竞态、取消、并发)。示例:
2. Redux Observable
原理:基于 RxJS 的响应式编程模型,将 Action 流视为 Observable 序列,通过操作符处理异步逻辑。
示例:
四、中间件的底层实现
1. applyMiddleware
函数
Redux 的 applyMiddleware
函数将多个中间件组合成一个增强后的 dispatch
方法:
2. compose
函数
compose
函数将中间件从右到左嵌套执行:
五、总结
Redux Thunk
拦截函数类型的 Action,执行异步逻辑并手动分发 Action。
简单异步操作(如 API 请求)
Redux Saga
使用 Generator 函数监听 Action,集中管理复杂异步流程。
复杂异步逻辑(如竞态、取消)
Redux Observable
基于 RxJS 的 Observable 流处理异步 Action。
响应式编程场景
通过中间件机制,Redux 可以灵活扩展其能力,支持异步操作、日志记录、状态持久化等功能。理解中间件的原理有助于开发者根据需求选择合适的工具,并编写高效可维护的状态管理代码。
最后更新于
这有帮助吗?