1、回顾上篇
Taro 项目拆分到多个分包,就是分别对A、B页面使用混合模式打包,步骤和把 Taro 项目作为一个完整分包一致。(Taro项目拆分到多个分包)
2、发现问题
A、B页面分别作为完整的分包,其中采用同一份状态的地方肯定不少,比如用户所属区域、用户token等,那么同步两个分包之间的状态就是重中之重的事情。
3、分布情况
项目各个包之间的关系以及状态分布大致情况如下:
很明显多个Taro分包之间虽然采用同一种状态管理技术但其状态却是不同的,每个分包只能改变其自己的分包状态,和其兄弟分包的状态是完全隔离开的。
4、解决方案
- 在项目全局状态中维护一份最新的actions(收集每一个分包的action并存储到原生小程序的状态中)
- 切换分包的时候将全局状态中维护的最新actions遍历执行dispatch。
熟悉redux都知道普通的action函数返回的是一个对象,类似{ type: "ADD", data: 10 }
,那么所有的分包想改变自身状态都需要通过dispatch(action)
, 那么收集并维护一份最新的actions数组并在切换分包的时候去遍历执行所有的action,就可以实现同步分包之间的状态,大体的思路就是如此。
细想后又会冒出以下几个问题:
-
如何在dispatch执行的时候收集这个action?
-
如何将收集到的action保存至全局状态?
-
如何知晓当下操作时分包之间的切换?又是哪两个分包之间的切换?
-
频繁切换分包的性能问题如何?
-
and so on …
- 如何在dispatch执行的时候去收集这个action?
首先想弄明白这个问题需要弄清楚redux的整体过程,具体流程如下:
关注更新时的状态变化:
- dispatch 一个 action 到 Redux store。
- store 用之前的 state 和当前的 action 再次运行 reducer 函数,并将返回值保存为新的 state。
在这个流程中能收集action的步骤只能是在dispatch中。通过redux的中间件可以拿到当前的action,也就可以执行收集操作。中间件流程如下: - 中间件的执行原理和koa中间件的执行原理类似,但是不是洋葱型的,而是半个洋葱,因为redux是单向执行的,走过去就完事了。就是将原来的dispatch函数封装处理后的形成新的dispatch函数,每一个中间件执行的操作都封装在新的dispatch函数中了。
通过中间件额外执行收集action的操作来解决第一个问题
- 如何将收集到的action保存至全局状态?
首先利用Taro.getApp()获取小程序全局唯一App对象。
方案一:将收集到的action对象无脑push到App对象的actions数组中,切换分包时候执行保存的所有action,执行完后清空actions数组。
方案二:将收集到的action对象保存到App对象的actions数组中,若已存在同类型action则直接替换,切换分包时候执行保存的所有action,无需清空actions。(不适用action类似自增功能,只适用于替换功能,相当于每一个action即最新的state)
方案三:结合以上两中方案进行优化,首先将类似自增这样的action的type声明到一个数组中,收集到的当前action进行判断是否是声明数组中的类型,若是则执行方案一,无脑push到全局actions中,若不是则先进行判断其action是否已经在全局actions中存在,若存在则删除存在的action,再将当前新的action存进全局actions的末尾,若不存在则直接将新的action存进全局actions的末尾。
- 如何知晓当下操作时分包之间的切换?又是哪两个分包之间的切换?
通过wx.onAppRoute在全局监听路由的变化,若命中路由变化条件,则通过全局eventBus去通知某个分包执行dispatch所有action操作。同时需要在每一个分包中写入具体的监听事件。
- 频繁切换分包的性能问题如何?
切换分包会遍历全局actions数组从而执行多次dispatch(action),每次执行dispatch会导致页面重新渲染吗?答案是不会。dispatch是同步的,react批处理的机制,为了将同一上下文中触发的更新合并为一个更新。
5、源码
项目地址:分包共享redux状态demo
6、结论
以上为本人对分包之间的redux状态共享的初探沉淀,同时感谢组长jh提供的思路。