dva model中的effect

在实际的开发中,计算新 state 时常常需要异步操作配合,比如说强制延时、异步网络请求数据(比如 ajax)等等。但是 reducer 需要是个纯函数,我们不能在 reducer 中写这些逻辑,破坏了这个机制后 dva 将无法工作。在 dva 框架下,effect 就是专门处理这些具有 “副作用” 的操作的执行单元。
effect 到底是什么呢 ?effect 是一个 dva 语境中的名词。和 reducers 类似,我们也可以在 dva model 中定义一个 effects 成员。
export default {
namespace: ‘some_namespace’,
state: {},
effects: { // 定义 effects 成员
‘someEffect’: function*() {},
‘someOtherEffect’: function*() {},
// …
},
reducers: {
// …
},
}
局部上看 effect 就是一个一个的 generator function。宏观上看,effect 是一层中间件。

effect 和 middleware
我们先展示 effect 是怎样作为中间件存在的。中间件是一种程序架构和分布式系统架构上的思想。目前来讲还没有个标准定义,笔者认为起码在程序架构领域下面一句话还是比较准确精炼的。
" Middleware is some code you can put between the framework receiving a request, and the framework generating a response. "
action 被 dispatch 之后就能够 直接 到达 reducer。为了保证 reducer 的纯粹性,但同时又能够处理副作用,就需要打破「直接」这个特性。effect 充当了这么一个中间层,当 action 被 dispatch 之后,会先到达 effect 处理副作用,然后该 effect 最终会促使新的 action 发送出去,这个新的 action 可能被其他的 effect 再捕获继续处理,也可能被 reducer 捕获并结束,无论怎样,最终处理逻辑的终点都将是 reducer。

我们知道 action.type 的构造是 namespace 名称 + / + reducer 名称,事实上 action.type 也可以是 namespace 名称 + / + effect 名称。对于视图层来讲,其实并不会感知 effect 和 reducer 的区别。视图层只是通过 action 描述想做什么,至于这个 action 之后是直接被 reducer 处理还是通过 effect 再到 reducer,视图层并不感知,也不应该关心。这样我们就做到了数据逻辑和视图逻辑的分离处理。

Generator function

我们再解释为什么 generator function 可以用来处理异步逻辑。其实 generator function 处理异步逻辑并不是 dva 的专利,在许多 js 框架中都用到了,最著名的就是 co。使用 generator function 处理异步也不是对语言特性的乱用,而是说 generator function 天然地就具备处理异步的特质。dva 中一个典型的 effect 的写法是:

getData: function* ({ payload }, { call, put }) {
const data = yield call(SomeService.getEndpointData, payload, ‘maybeSomeOtherParams’);
yield put({ type: ‘getData_success’, payload: data });
}

先说结论:当这个 generator function 被执行时,执行的流程 看上去 会是同步的!入参有两个对象,第一个对象就是匹配这个 effect 的 action 对象,因此可以取到约定的 payload 这个字段,第二个对象是 effect 原语集,其中 call, put 最为常用。generator function 入参中的两个对象都是在运行时由 dva 注入到 generator function 中的。call 其实是一个函数,和 yield 关键字配合使用处理异步逻辑,call 第一个参数是一个函数,要求函数返回 Promise,之后的参数是该函数调用时的入参。yield call 调用后就阻塞了,Promise 被解析后,得到异步调用的结果,存储到 data 中,然后程序才能继续进行。看到下面一行又执行了 put。put 也是一个函数,put 和 yield 配合使用,用来派发一个 action,和 dispatch 的功能 一模一样!只不过是在 effect 函数中使用而已。

注意:yield put 派发的 action 如果是为了触发 同 model 中的其他 effect/reducer 执行,不需要指定 namespace 名称。

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值