Maison > interface Web > js tutoriel > le corps du texte

Une introduction à l'utilisation de RxJS pour gérer l'état de l'application React

不言
Libérer: 2019-04-03 10:24:59
avant
2817 Les gens l'ont consulté

Cet article vous présente une introduction à l'utilisation de RxJS pour gérer le statut des applications React. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

À mesure que les applications frontales deviennent de plus en plus complexes, la gestion des données des applications est devenue un problème inévitable. Lorsque vous êtes confronté à des applications frontales à grande échelle avec des scénarios commerciaux complexes, des changements fréquents de la demande et diverses données d'application interdépendantes et dépendantes , comment allez-vous gérer les données d'état de l'application ?

Nous pensons que les données des applications peuvent être grossièrement divisées en quatre catégories :

  • Événements : données générées en un instant. Les données sont détruites immédiatement après leur consommation et ne sont pas stockées.
  • Asynchrone : Données obtenues de manière asynchrone ; similaires aux événements, ce sont des données instantanées et ne sont pas stockées.
  • Statut : les données qui changent avec le temps et l'espace stockeront toujours une valeur actuelle/dernière valeur.
  • Constante : données fixes.

RxJS est naturellement adapté à l'écriture de programmes asynchrones et basés sur des événements, alors comment gérer les données d'état ? Dois-je quand même utiliser RxJS ? Est-ce adapté ?

Nous avons étudié et découvert les excellentes solutions de gestion d'état existantes dans la communauté front-end, et nous avons été inspirés par les idées et les pratiques partagées par certains experts sur l'utilisation de RxJS pour concevoir la couche de données :

  1. L'utilisation de RxJS peut complètement implémenter des fonctions telles que Redux, Mobx et d'autres données d'état de gestion.
  2. Les données de l'application ne sont pas seulement des statuts, mais aussi des événements, des asynchrones, des constantes, etc. Si l'ensemble de l'application est exprimé par observable, vous pouvez utiliser les fonctionnalités réactives et basées sur des séquences de RxJS pour assembler et combiner librement différents types de données de manière fluide, en extrayant les données possibles de manière plus élégante et plus efficace. modèles.

Pour les deux raisons ci-dessus, nous avons finalement décidé de concevoir une solution de gestion du statut des candidatures basée sur RxJS.

Introduction au principe

Pour la définition de l'État, on pense généralement que l'État doit remplir les trois conditions suivantes :

  1. est un ensemble avec plusieurs valeurs .
  2. peut convertir la valeur via event ou action pour obtenir une nouvelle valeur.
  3. Il existe la notion de « valeur actuelle ». Généralement, seule la valeur actuelle, c'est-à-dire la dernière valeur, est exposée au monde extérieur.

Alors, RxJS est-il adapté à la gestion des données de statut ? La réponse est oui !

Tout d'abord, parce que Observable lui-même est une collection push de plusieurs valeurs, la première condition est remplie !

Deuxièmement, nous pouvons implémenter un dispatch action qui utilise le modèle observable pour pousser les données afin de satisfaire la deuxième condition

Comme nous le savons tous ! , RxJS in > peut être divisé en deux types : observable

 : Le producteur (cold observable) qui pousse la valeur vient de l'intérieur producer. Le nombre de valeurs observable

    qui seront poussées et le type de valeurs qui seront poussées ont été définis lors de la création de
  • et ne peuvent pas être modifiés. observable
  • a une relation individuelle avec l'observateur (producer), qui est en monodiffusion. observer
  • Chaque fois qu'il y a un
  • abonnement, observer poussera plusieurs valeurs prédéfinies vers producer dans l'ordre. observer

 : Poussez la valeur hot observable de l'extérieur producer. observable

    Combien de valeurs seront poussées, quelles valeurs seront poussées et quand seront poussées sont inconnus au moment de la création.
  • et producer ont une relation un-à-plusieurs, c'est-à-dire multidiffusion. observer
  • Chaque fois qu'il y a un
  • abonnement, observer sera enregistré dans la liste des observateurs, de la même manière que observer fonctionne dans d'autres bibliothèques ou langues. addListener
  • Lorsque le
  • externe est déclenché ou exécuté, la valeur sera poussée vers tous les producer en même temps ; c'est-à-dire que tous les observer partagent la valeur poussée par observer. Le hot observable fourni par

RxJS est un type spécial de BehaviorSubject, qui expose la fonction d'interface hot observable pour pousser les données et a le concept de « valeur actuelle » ; La dernière valeur envoyée à next est enregistrée Lorsqu'un nouvel observateur s'abonne, la "valeur actuelle" sera immédiatement reçue de observer. BehaviorSubject

Ensuite, cela montre qu'il est possible d'utiliser pour mettre à jour l'état et enregistrer la valeur actuelle de l'état, et la troisième condition est également remplie. BehaviorSubject

Implémentation simple

Veuillez consulter le code suivant :

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);
Copier après la connexion
L'exécution de la console de code imprimera trois valeurs :

Console

 1
 2
 4
Copier après la connexion
Le code ci-dessus implémente simplement un exemple de gestion d'état simple :

    Valeur initiale de l'état : 1
  • Valeur de l'état après l'exécution de
  •  : 2plus
  • Valeur du statut après l'exécution de
  •  : 4toDouble
La méthode d'implémentation est assez simple, c'est-à-dire utiliser

pour exprimer la valeur actuelle du statut : BehaviorSubject

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

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

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

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

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;
    }
  }
});
Copier après la connexion

更新状态

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

dispatch("count", {
  type: "plus"
})
Copier après la connexion

异步数据

RxJS的一大优势就在于能够统一同步和异步,使用observable处理数据你不需要关注同步还是异步。

下面的例子我们使用操作符frompromise转换为observable

指定observable作为状态的初始值(首次推送数据)

const todos$ = state({
  name: "todos",
    
  // `observable`推送的数据将作为状态的初始值
  initial: from(getAsyncData())
    
  //...
  
});
Copier après la connexion

producer推送observable

const todos$ = state({
  name: "todos",
    
  defaultValue: []
    
  // 数据推送的生产者函数
  producer(next, value, action) {
    switch (action.type) {
      case "getAsyncData":
        next(
          from(getAsyncData())
        );
        break;
    }
  }
});
Copier après la connexion

执行getAsyncData之后,from(getAsyncData())的推送数据将成为状态的最新值。

衍生状态

由于状态todos$是一个observable,所以可以很自然地使用RxJS操作符转换得到另一个新的observable。并且这个observable的推送来自todos$;也就是说只要todos$推送新数据,它也会推送;效果类似于Vue的计算属性。

// 未完成任务数量
const undoneCount$ = todos$.pipe(
  map(todos => {
    let _conut = 0;
    todos.forEach(item => {
      if (!item.check) ++_conut;
    });
    return _conut;
  })
);
Copier après la connexion

React视图渲染

我们可能会在组件的生命周期内订阅observable得到数据渲染视图。

class Todos extends React.Component {
  componentWillMount() {
    todos$.subscribe(data => {
      this.setState({
        todos: data
      });
    });
  }
}
Copier après la connexion

我们可以再优化下,利用高阶组件封装一个装饰器函数@subscription,顾名思义,就是为React组件订阅observable以响应推送数据的变化;它会将observable推送的数据转换为React组件的props

@subscription({
  todos: todos$
})
class TodoList extends React.Component {
  render() {
    return (
      <p className="todolist">
        <h1 className="header">任务列表</h1>
        {this.props.todos.map((item, n) => {
          return <TodoItem item={item} key={item.desc} />;
        })}
      </p>
    );
  }
}
Copier après la connexion

总结

使用RxJS越久,越令人受益匪浅。

  • 因为它基于observable序列提供了较高层次的抽象,并且是观察者模式,可以尽可能地减少各组件各模块之间的耦合度,大大减轻了定位BUG和重构的负担。
  • 因为是基于observable序列来编写代码的,所以遇到复杂的业务场景,总能按照一定的顺序使用observable描述出来,代码的可读性很强。并且当需求变动时,我可能只需要调整下observable的顺序,或者加个操作符就行了。再也不必因为一个复杂的业务流程改动了,需要去改好几个地方的代码(而且还容易改出BUG,笑~)。

所以,以上基于RxJS的状态管理方案,对我们来说是一个必需品,因为我们项目中大量使用了RxJS,如果状态数据也是observable,对我们抽象可复用可扩展的业务模型是一个非常大的助力。当然了,如果你的项目中没有使用RxJS,也许ReduxMobx是更合适的选择。

这套基于RxJS的状态管理方案,我们已经用于开发公司的商用项目,反馈还不错。所以我们决定把这套方案整理成一个js lib,取名为:Floway,并在github上开源:

  • github源码:https://github.com/shayeLee/floway
  • 使用文档:https://shayelee.github.io/floway

【相关推荐:react视频教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal