使用RxJS管理React应用状态的介绍


本文摘自PHP中文网,作者不言,侵删。

本篇文章给大家带来的内容是关于使用RxJS管理React应用状态的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

随着前端应用的复杂度越来越高,如何管理应用的数据已经是一个不可回避的问题。当你面对的是业务场景复杂、需求变动频繁、各种应用数据互相关联依赖的大型前端应用时,你会如何去管理应用的状态数据呢?

我们认为应用的数据大体上可以分为四类:

  • 事件:瞬间产生的数据,数据被消费后立即销毁,不存储。
  • 异步:异步获取的数据;类似于事件,是瞬间数据,不存储。
  • 状态:随着时间空间变化的数据,始终会存储一个当前值/最新值。
  • 常量:固定不变的数据。

RxJS天生就适合编写异步和基于事件的程序,那么状态数据用什么去管理呢?还是用RxJS吗? 合不合适呢?

我们去调研和学习了前端社区已有的优秀的状态管理解决方案,也从一些大牛分享的关于用RxJS设计数据层的构想和实践中得到了启发:

  1. 使用RxJS完全可以实现诸如Redux,Mobx等管理状态数据的功能。
  2. 应用的数据不是只有状态的,还有事件、异步、常量等等。如果整个应用都由observable来表达,则可以借助RxJS基于序列且可响应的的特性,以流的方式自由地拼接和组合各种类型的数据,能够更优雅更高效地抽象出可复用可扩展的业务模型。

出于以上两点原因,最终决定基于RxJS来设计一套管理应用的状态的解决方案。

原理介绍

对于状态的定义,通常认为状态需要满足以下3个条件:

  1. 是一个具有多个值的集合。
  2. 能够通过event或者action对值进行转换,从而得到新的值。
  3. 有“当前值”的概念,对外一般只暴露当前值,即最新值。

那么,RxJS适合用来管理状态数据吗?答案是肯定的!

首先,因为Observable本身就是多个值的推送集合,所以第一个条件是满足的!

其次,我们可以实现一个使用dispatch action模式来推送数据的observable来满足第二个条件!

众所周知,RxJS中的observable可以分为两种类型:

cold observable: 推送值的生产者(producer)来自observable内部。

  • 将会推送几个值以及推送什么样的值已在observable创建时被定义下来,不可改变。
  • producer与观察者(observer) 是一对一的关系,即是单播的。
  • 每当有observer订阅时,producer都会把预先定义好的若干个值依次推送给observer

hot observable: 推送值的producer来自observable外部。

  • 将会推送几个值、推送什么样的值以及何时推送在创建时都是未知的。
  • producerobserver是一对多的关系,即是多播的。
  • 每当有observer订阅时,会将observer注册到观察者列表中,类似于其他库或语言中的addListener的工作方式。
  • 当外部的producer被触发或执行时,会将值同时推送给所有的observer;也就是说,所有的observer共享了hot observable推送的值。

RxJS提供的BehaviorSubject就是一种特殊的hot observable,它向外暴露了推送数据的接口next函数;并且有“当前值”的概念,它保存了发送给observer的最新值,当有新的观察者订阅时,会立即从BehaviorSubject那接收到“当前值”。

那么这说明使用BehaviorSubject来更新状态并保存状态的当前值是可行的,第三个条件也满足了。

简单实现

请看以下的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

import { BehaviorSubject } from 'rxjs';

 

// 数据推送的生产者

class StateMachine {

  constructor(subject, value) {

    this.subject = subject;

    this.value = value;

  }

 

  producer(action) {

    let oldValue = this.value;

    let newValue;

    switch (action.type) {

      case 'plus':

        newValue = ++oldValue;

        this.value = newValue;

        this.subject.next(newValue);

        break;

      case 'toDouble':

        newValue = oldValue * 2;

        this.value = newValue;

        this.subject.next(newValue);

        break;

    }

  }

}

 

const value = 1;  // 状态的初始值

const count$ = new BehaviorSubject(value);

const stateMachine = new StateMachine(count$, value);

 

// 派遣action

function dispatch(action) {

  stateMachine.producer(action);

}

 

count$.subscribe(val => {

  console.log(val);

});

 

setTimeout(() => {

  dispatch({

    type: "plus"

  });

}, 1000);

 

setTimeout(() => {

  dispatch({

    type: "toDouble"

  });

}, 2000);

执行代码控制台会打印出三个值:

1

2

3

4

5

Console

 

 1

 2

 4

上面的代码简单实现了一个简单管理状态的例子:

  • 状态的初始值: 1
  • 执行plus之后的状态值: 2
  • 执行toDouble之后的状态值: 4

实现方法挺简单的,就是使用BehaviorSubject来表达状态的当前值:

  • 第一步,通过调用dispatch函数使producer函数执行
  • 第二部,producer函数在内部调用了BehaviorSubjectnext函数,推送了新数据,BehaviorSubject的当前值更新了,也就是状态更新了。

不过写起来略微繁琐,我们对其进行了封装,优化后写法见下文。

使用操作符来创建状态数据

我们自定义了一个操作符state用来创建一个能够通过dispatch action模式推送新数据的BehaviorSubject,我们称她为stateObservable

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

const count$ = state({

  // 状态的唯一标识名称

  name: "count",

     

  // 状态的默认值

  defaultValue: 1,

     

  // 数据推送的生产者函数

  producer(next, value, action) {

    switch (action.type) {

      case "plus":

        next(value + 1);

        break;

      case "toDouble":

        next(value * 2);

        break;

    }

  }

});

更新状态

在你想要的任意位置使用函数dispatch派遣action即可更新状态!

阅读剩余部分

相关阅读 >>

如何使用javascript完成省市联动效果

javascript怎么比较大小

javascript实现无限级递归树的代码示例

javascript怎么定义数据类型

javascript如何判断对象是否数组

javascript怎么实现浮动窗口

javascript异步编程方法有哪些

javascript常用的数据类型有哪些

360如何打开javascript

什么是并发控制?javascript中如何实现并发控制?

更多相关阅读请进入《mobx》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...