破题

Context 存储变量
缺点:数据源追溯难,确认变动点难;与组件耦合度高,不利于组件复用和测试。

Flux

Flux 是一种基于 单向数据流 的架构。
面试 - 8- 列举React 状态管理框架 - 图1

  • View:视图层,React 组件;
  • Store:数据层,维护了数据和数据处理的逻辑;
  • Dispatcher:管理数据流动的中央枢纽。每个 Store 提供一个回调。当 Dispatcher 接收一个 Action 时,所有的 Store 接收注册表中的 Action,然后通过回调产生数据。
  • Action:事件通知,通常用 type 标记。

流程:Store 存储了视图层所有的数据,当 Store 改变后引起 View 层更新。若在视图层触发 Action,如点击按钮,当前页面数据会发生改变。Action 会被 Dispatcher 进行统一的收发处理,传递给 Store 层。由于 Store 层已注册过相关的 Action 的处理逻辑,处理对应的内部状态变化后,会触发 View 层更新。
优点:单向数据流,解决了 MVC 中数据流向不清问题。

Redux

Redux 三原则:

  1. 单一数据源:整个应用的 state 被存储在一颗 object tree 中,且这个 object tree 只存在于唯一的一个 Store 中。
  2. 纯函数 Reducer:即为了描述 Action 是如何改变状态树,编写一个纯函数的 Reducer。
  3. state 是只读的:改变 state 的唯一方法是触发 Action,Action 是一个用于描述已发生事件的普通对象。

优点:

  1. 结果可预测
  2. 代码结构严谨易维护
  3. 模块分离清晰,且小函数结构易编写单元测试
  4. Action 的触发方式,可回溯,易定位问题
  5. 单一数据源使服务端同构变得更为容易
  6. 社区方案多,生态繁荣

Redux 的调试工具 Redux DevTools,时间回溯。


问:Redux 如何解决副作用???
解决副作用的方案分为两类:

  1. 在 Dispatch 时有个一个 middleware 中间件层,拦截分发的 Action 并添加额外的复杂行为,还可添加副作用;
    流行方案:Redux-thunk,其作用是处理异步 Action,面试中要求独立编写。 ```tsx function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => (next) => (Action) => { if (typeof Action === ‘function’) { return Action(dispatch, getState, extraArgument); } return next(Action); } }

const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware;

export default thunk; ``` 如上代码,Redux-thunk 通过添加中间件来判断 Action 是否为函数:

  • 若是函数,则 Dispatch 将当前整个 state 以及额外的参数传入其中;
  • 若不是函数,继续流转 Action;

以上是最早最经典的处理 Redux 副作用的方案,也可自定义 Store 的 middleware。
若 Action 是一个数组,或 Promise 该如何处理?Action 可以是 数组,Promise,迭代器,rxjs,如 Redux-Saga,Redux-Promise,Redux-Observable等。

  1. 允许 Reducer 层直接处理副作用。
    Redux Loop 借鉴 Elm,Elm 处理副作用在 update 层,此种设计叫 分形架构。

关于 Redux 的工程化统一解决方案:

  • 国外流行 rematch,他提供标准的范式写 Redux,具体案例 ,rematch 的模块更内聚,插件更丰富。
  • 国内流行 Dva

    MobX

    相关API 文档:MobX-01MobX-02
    MobX 是通过监听数据的属性变化,直接在数据上更改来触发 UI 的渲染。
    MobX 的 响应式原理 与 Vue 相同。
    MobX 的监听方式:

  • MobX 5 之前,Object.defineProperty

  • MobX 5 之后,Proxy

面试 - 8- 列举React 状态管理框架 - 图2

进阶

手写 Redux,手写时,需注意两个地方:

  1. createStore,通过 createStore,注入 Reducer 与 middleware,生成 Store 对象;
  2. Store 对象的 getState、subscribe、diapatch 函数。getState 获取当前状态树,subscribe 函数订阅状态树变更,diapatch 函数发送 Action。

在实现上尽量采用 纯函数 实现方案,参考 Redux4.x