《redux实战》第1章:redux介绍

397 阅读9分钟

本章学习内容已规整到对应专栏

1、什么是状态

React具有本地状态的概念,这个状态又叫做组件状态,组件状态可以轻松管理单个组件的行为。然而如今的SPA,往往会伴随着复杂的状态网,在普通的react架构中,如果要做到这种复杂的状态网,往往需要自顶级组件将某些子组件需要的状态,经过层层props传递后,抵达目标子组件,这就会导致不相关的组件之间出现大量的数据移动,从而导致后期代码维护和测试用例会变得难以为继。

基于此,脸书推出了Flux,这个用于Web应用程序架构模式,redux正是基于这种架构模式被构造出来,并且成功成为了众多状态管理库中的胜出者。

2、什么是Flux

Flux是Jing Chen为Facebook开发的一种架构模式,Flux是作为主流的JS MVC模式的替代品而被开发,它试图解决状态的不可预知性以及模型和视图紧密耦合的架构脆弱性。于是,Flux没有采用双向数据绑定(双向数据绑定在某种情况下,给定的视图能够更新一个或多个模型,而这个或这些模型又可以更新更多的视图,这就会无法很好把握预期的结果了),而是采用了单项数据流。

Flux要求对状态的所有修改遵循单一的路径,而不允许每个视图与对应的模型进行交互。比如:当用户单击表单中的Submit按钮时,会向应用程序的唯一dispatcher发送一个action。然后,该dispatcher将数据发送到合适的数据存储进行更新,一旦更新后,视图将会知道要渲染的新数据。

1)action: 状态的每次改变都始于一个action,action是描述应用程序事件的JS对象,它们通常由用户交互或服务器事件(如:HTTP响应)产生。

2)dispatcher: Flux应用程序中的所有数据流都是通过单一的dispatcher进行回击,dispatcher自身的功能很少,其目的只是为了接收所有的action,并将它们发送到对应的每个已注册的store。

3)store: 每个store管理一个域的状态。比如:电子商务网站中,可能会找到一个购物车的store和一个产品store,一旦把一个store注册到dispatcher,它就开始接收action,当store接收到它关心的action类型时,就行进行相应的更新。而store一旦产生更改,就会广播一个事件,让视图使用新的状态进行更新。

4)视图: Flux可能在设计时考虑了react,但视图并不需要react组件。对视图而言,它们只需要订阅要显示的数据的store。Flux文档鼓励使用“控制器-视图”模式,借助一个顶级组件处理与store的通信,并将数据传递给子组件。

Flux指定数据必须单向流动.png

3、什么是reudx

官方解答 => redux是JS应用程序的可预测状态的容器

主要目的 => 为应用程序中的数据带来一致性和可预测性

redux将状态管理划分成一下三个状态:

  • store将应用程序的所有状态都存储在单个对象中(这个对象通常被称为对象树);
  • 只能使用action来更新store,action是描述事件的对象
  • reducer函数(纯函数)指定了如何转换应用程序的状态,它接收store中的当前状态和一个action,并返回更新后的下个状态。

1)react和redux

说起redux,大家总会不自觉将其与react联系在一起,其实两者是完全解耦的,它们之间需要使用react-redux来进行绑定,如下图所示: react和redux的绑定.png 此外,react也可以与其他JS框架一起使用,如:angular、ember等。

2)三个原则

  • 单一数据源。与Flux架构规定的各种域的store不同,redux在store内部的对象中管理着整个应用程序的状态,使用单一的store具有重要的意义,可以在单个对象中表示整个应用程序状态的能力;
  • 状态是只读的。与Flux一样,action是应用程序状态改变的唯一方式,在不使用action的情况下,其他的一些方式(如:Ajax调用)是不会引起状态的改变的。并且在react中,action不会导致store中的数据产生突变,相反,每个action都会产生一个新的state来替换当前得state。
  • 状态的改变由纯函数(reducer)进行。reducer是纯函数,在给定相同输入的情况下,它们总是产生同样的结果,并且过程不会改变任何数据,可以通过reducer接收派发的action。

3)工作流

redux工作流.png action: 用户在触发一个事件后,将通过派发action来代表这个事件启动的过程。action表示应用程序中事件的js对象字面量,如下所示:

{
    type: 'CREATE_EVENT',
    payload: {
        body: 'All that is gold does not glitter'
    }
}

其实可以看出action是一个具有以下两个属性的对象。
- type:表示正在执行的action类别的字符串,按照惯例,type属性的值需要大写,并使用下划线作为分隔符;
- payload:提供执行action所需数据的一个对象

记住!action是用来描述一个事件,它不知道也不关心下游会发生什么。

reducer: 它是一个简单的函数,负责更新状态以响应action的函数,接收当前状态和一个action作为参数,并返回下一个状态。具体流程如下图所示: reducer处理状态的流程.png

一个复杂的应用程序,通常需要实现若干个reducer,每一个都会关注状态数的不同部分,这些reducer最终会被联合组成一个root reducer(通过combinereducers API来联合所有的reducer)。

store: reducer描述了如何更新状态以响应action,但它们无法直接修改状态,修改状态的这种权力仅限于store拥有。在Redux中,应用程序状态存储在单个对象中,store拥有以下几个主要角色,包括:

  • 持有应用程序的状态;
  • 提供一种访问状态的方式;
  • 提供一种方式来指定对状态的更新,一般store会要求派发一个action来修改状态;
  • 允许其他实体订阅更新,如:React组件在状态更新时,重新渲染视图。通过react-redux提供的视图绑定可以接收来自store的更新,并在组件中对其做出响应。

reducer处理action并计算下一个状态,然后store更新自身,并将新状态广播给所有已注册的监听者。 redux架构图.png 从上图可以看出,与视图的交互会引发一个action,这个action会通过一个或多个reducer进行过滤,并在store中生成新的状态树,一旦状态更新,视图将意识到有新的数据要渲染,这就是redux的整个工作流程了。


关于action、reducer以及store的工作流,还是举个具体的例子说明一下会更清楚吧!比如:页面有一个展示用户帖子总数、已发贴子的列表以及和拥有发帖功能的页面(具体如下图所示),当用户点击发布新帖,并填写了相关具体内容,点击【发布新贴】之后,就会派发一个发布新贴的action,reducer监控到派发的对应action之后,就会更新状态以响应对应的action行为,然后store会根据reducer返回的新状态来更新自身的状态树,从而将新状态广播给视图层用到该状态的地方。 帖子例子.png

4、为什么要用reudx

redux是一个小型且易学的状态管理库,可以生成高度可预测、可测试并可调试的应用程序。

1)可预测性

redux最大的卖点是为处理应用程序的复杂状态带来了条理性。redux架构提供了一种直观的方式来概念化并管理状态,一次一个action,无论应用程序的大小如何,单向数据流内的action会让针对单一store的更改是可预测的。

2)开发者体验

hot-loading和time-travel调试工具为开发人员提供了更快的开发周期,无论是构建新功能还是寻找bug。

3)可测试性

需要编写的redux代码主要是函数,其中许多都是纯函数,每一块都可以轻松分解并隔离进行单元测试。

4)学习曲线

redux是原生react的自然进阶,体积非常小,只公开了少量API用于完成工作。

5)体积

redux压缩后的体积小于7KB。

5、何时应该使用redux和备选方案

1)何时使用redux

需要知道的是,使用redux的代价是会产生很多的模板代码,以及相比react本地组件状态更高的复杂度。关于何时使用redux,redux的联合创始人Dan Abramov的建议是:开始时不使用redux,仅在遭遇足够多的状态管理痛点,能证明包含redux是合理的之后才引入它。 对于一些没有复杂数据需求的较小的应用程序,这时候不使用redux,而使用普通react的状态管理可能更加合适。

那关于状态管理的痛点是什么呢?

场景1:在几层不会使用任何数据的组件间传递数据;

场景2:处理在应用程序不相关部分之间的共享和同步数据。

对于这些场景,如果使用react来实现,会多出很多非必要的数据传输过程。所以,如果知道构建的特定功能是redux擅长的,redux很可能会是不错的选择;如果知道应用程序会有复杂的状态,并且需要撤销和重做功能,请直截了当地引入redux;如果需要服务端渲染,请优先考虑redux。

2)redux的备选方案

redux的备选方案有很多种,比如:Reflux、Alt、MobX等等。这里介绍下MobX。

MobX为状态管理提供了一种函数响应式解决方案。与Flux类似,MobX使用action修改状态,但组件会对变化后的或可观察的状态做出响应。具体的内容,可以参见:MobX官网