Redux Model 探索

Dva 的 Model 设计我一直很不喜欢,感觉还是很繁琐,而且经常需要切换文件查看以填写正确的字面量。所以我一直在努力把 Model 进行重写,在不破坏 DVA 本身的前提下。

所以我写了个库 @ali/dva-model,现在还没有开源出来,还在内部测试中。它通过 @Model 装饰器,可以让你用另一种写法来定义 Model,但最终这个 Model 产生的实际还是 Dva 要求的 Model。

下面对比说明下我做了什么改进,后面有几张截图,左边是 Dva Model 的写法和用法,右边则是改进后的写法用法。

定义一个 Instance Model

这个 Model 存在三个状态 instancestotaltest。其中 instancestotal 是服务端返回的数据,test 是页面状态,但也存放到该 Model 上。

1

定义一个 Test Model

这个 Model 只存放一个状态 loading,同时还有一个 effects,去调用上面 Model 的 getInstance 方法并设置 loading 状态。

2

Model 注册

DVA 中注册 Model 需要两个步骤,但是右边的只需要把 DVA 实例传入 createDvaModel 方法即可。在 @Model 时就已经自动完成了 Model 注册。

3

Component Connect

不同于 DVA 的 Model 使用,在后者中,Model 实例的 effects 其实是一个 ActionCreator,所以你不仅可以直接在另一个 Model 中去调用,也可以在 Connect 的时候直接像右边那样写。

4

仔细对比,其实会发现,每个文件,新的 Model 写法的代码行数都会更少了,而且你可能还没有注意到的是:

  1. 没有字面量,Model 实例下的 effects 其实就是一个 ActionCreator,虽然表面看起来不是。这意味着connect 以及跨 Model 调用 effects 的时候不需要去写 payload => dispatch({ type, payload }) 这样的句式。
  2. 出现了不少的 this,但是 this 的出现其实都挺恰到好处,他都能显示的指向当前 Model 的 state 或者 effects,编辑器可以给你自动补全提示。
  3. 可以在 effects 中直接进行 state 修改的操作,你可以不用为每个 effects 获取得到的数据都去写一个 reducer 来执行更新操作。
  4. 在 reducers 中,你可以直接通过 this.a.b.c 这样来修改 state。不同于 effects,你可以修改深层次的属性,这里基于 immer 实现。

但是,问题也显而易见,就是黑魔法实在太多了,包括:

  1. Model 实例化后其实是类似左边的结构,@Model 修改了实例化返回的结果。
  2. Model effects 中的 this 并不是指向当前实例,@Model 修改了 this,这个 this 包含了当前 Model 的所有 ActionCreator,同时 this 上面会对你 Model 所有的 stateKey 进行 setter 定义操作,这样当你修改 this.xxx(你以为你在直接修改当前实例的 xxx),其实是触发了 setter 从而 dispatch 一个内建的 reducer 去修改 state。