Redux原理:为达目标,步步抽象

1,588 阅读5分钟

前言

听说没什么问题是加一层抽象解决不了的。因此本文参考《React小书》总结了此文,建议是将其作为辅助理解工具。

Redux 解决什么问题?

问题概述:模块又需要共享数据,对共享状态的操作不可预料,导致debug困难。 描述:APP应用,有A、B、C...100个模块,我们都需要用到全局Store,A可能去改,B也可能去改,出现数据不在预期范围的时候,根本不知道这100个模块哪个去修改时出现了问题,这就是debug困难了。

解决上述问题的方案是什么?

  • 抽象一层读取、修改数据的统一入口和方式,数据是全局的。
  • 抽象出修改的行为过程,只留下修改部分,其它逻辑不需要重复编码。

如何实现的(抽象过程)?

(1)dispatch 数据改写入口

抽象原因:state数据需要共享所以是全局的,但是任何模块都可以随意去修改会造成不可预料的影响。
抽象过程:统一状态修改入口抽象action和dispatch,只能通过dispatch分发action去改变状态state。
抽象结果

  • 每个地方要修改state从 直接修改全局变量 ===> dispatch action(action要事先定义好类型,和入参)
  • 每一次dispatch以后要重新调用一次渲染,让所有的模块更新

(2)写控制了入口,读就要变成“只读”,提供getState。最好跟写方法放在一起管理,抽象createStore统一管理。

抽象原因和过程

  • state状态已经控制了修改方式必须为dispatch action,那么全局状态需要提供“只读”的方式读取获取当前数据,不能通过全局变量得到,如果能通过变量读取,那么就可以进行改写。所以抽象createStore函数,管理状态内容state(store存储内容)的读、写。
  • 抽象必须是抽象出通用的东西,上一步在dispatch中需要根据action去判断如何修改状态,具体修改状态的代码是定制化的,只有根据action去修改state是一致的,所以抽象出来的dispatch入参是action,调用具体的修改函数修改状态,修改函数需要从外部传入,这就相当于原来在dispatch中具体修改状态的代码抽象出来一层,reducer(即stateChanger)。 抽象结果
  • createStore 初始化数据,提供读getState、写状态dispatch的方法。
  • 新增reducer层,用来实施具体的状态变更。

(3)更新事情是重复的,抽象到createStore,每次状态更新时自动调用

抽象原因:每次dispatch状态更新后需要重新调用render操作是一致的,既然是一致的东西就可以抽象成同一件事情去做,并且要使它使自动化的事情。
抽象过程: 既然是dispatch一次就操作一次,那就放在dispatch中做。在状态变更的最后一步增加一步触发模块(页面)更新的操作。
抽象结果: createStore 提供一个类方法,可以将事件传给内部变量listeners,在dispatch后进行调用。
(这里产生了一个问题,为什么不能像state、reducer一样用参数的方法传递更新事件。如果不这么设计会不会造成不良影响?如果参数传递,那么一开始就需要确定?因为createStore主要是管理state,入参只设计与state相关内容?)

(4)性能优化,通过判断减少不必要的执行。

抽象原因:优化性能,缓存旧的state,得到新的state以后进行比较。如果没有变化,则不进行相应的数据变化后事件。
抽象结果:要求我们的stateChange是一个纯函数,不要带来改变原来的oldState。这样才能够做新旧State比较。

(5)写法优化,通过参数合并能合并的代码。

抽象原因:优化写法,通过reducer创建初始值。
抽象结果:state默认null,createStore仅接受stateChange(即reducer)函数。

(6)强化功能,异步数据流、中间件

异步数据的处理反正是按照中间件实现的,不多说。毕竟我们的reducer不能有副作用,所以不能参与去获取数据。
抽象原因:应该是实际需要吧,我们需要获取异步参数、需要监控具体的action发生等等。
抽象过程:所有这些有个共同点,就是所有需要这些功能的APP使用方式都是一样的,所以不需要重复代码了,抽出个中间件,即插即用。redux核心第一点,修改入口控制在dispatch,其他都是为了解决这一点引申出来的。所以我们的中间件也是在dispatch上做文章,applyMiddleware就是在纯dispatch action修改数据上添加功能。例如thunkmiddleware的核心是dispatch可以传入function,检测到是function的时候执行里面代码,里面可能就去获取数据即执行副作用了,执行完副作用以后再真正调用dispatch action修改状态。为了我们能够做到多个中间件一起使用,每一个中间件的执行返回都是dispatch,下一个中间件可以再在dispatch上做文章。 (中间件部分看源码应该会更好理解)

思路的收获

  • 抽象是个好东西:代码上重复的行为努力抽象成统一方法、自动化方法。
  • 如何抽象?相关的东西放到一起处理,形成整体;抽象出来的东西最终会是一个任务流程,用户只需要填充任务流中的具体执行任务。
  • 函数内部获取外部信息的方式:传参、提供订阅方法subscribe