ホームページ  >  記事  >  ウェブフロントエンド  >  RxJS を使用して React アプリケーションの状態を管理する方法の概要

RxJS を使用して React アプリケーションの状態を管理する方法の概要

不言
不言転載
2019-04-03 10:24:592813ブラウズ

この記事では、RxJS を使用して React アプリケーションのステータスを管理する方法を紹介します。一定の参考値があり、困っている友人は参照できます。お役に立てれば幸いです。

フロントエンド アプリケーションがますます複雑になるにつれて、アプリケーション データを管理する方法は避けられない問題になっています。複雑なビジネス シナリオ、頻繁な需要の変化、相互に関連し依存するさまざまなアプリケーション データを備えた大規模なフロントエンド アプリケーションに直面した場合、アプリケーションのステータス データをどのように管理しますか? 私たちは、アプリケーション データは大きく 4 つのカテゴリに分類できると考えています:

イベント: 瞬間的に生成されるデータ、データは消費後すぐに破棄され、保存されません。
  • 非同期: 非同期で取得されるデータ。イベントと同様、瞬間的なデータであり、保存されません。
  • ステータス: 時間と空間とともに変化するデータには、常に現在の値/最新の値が保存されます。
  • 定数: 固定データ。
RxJS

は当然、非同期プログラムやイベントベースのプログラムを作成するのに適しています。では、状態データをどのように管理するのでしょうか?やはり ##RxJS を使用する必要がありますか?適切ですか? 私たちは、フロントエンド コミュニティですでに利用可能な優れた状態管理ソリューションについて調査して学びました。また、RxJS

を使用したデータ設計について一部の専門家が共有したアイデアや実践からも学びました。インスピレーション:

RxJS
    を使用すると、状態データを管理するための
  1. ReduxMobx などの関数を完全に実装できます。 アプリケーション データにはステータスだけでなく、イベント、非同期、定数なども含まれます。アプリケーション全体が observable
  2. で表現されている場合、
  3. RxJS のシーケンスベースの応答機能を利用して、さまざまな種類のデータをストリーミング方式で自由に接続および結合できます。再利用可能でスケーラブルなビジネス モデルをよりエレガントかつ効率的に実現します。 上記の 2 つの理由により、最終的には
  4. RxJS
に基づいてアプリケーションのステータスを管理するソリューションを設計することにしました。

原理導入

状態の定義については、一般に状態は次の 3 つの条件を満たす必要があると考えられています。

は複数の値を持つ集合です。 。

    は、
  1. event
  2. または
  3. action を通じて値を変換して、新しい値を取得できます。 「現在値」という概念がありますが、一般的には現在値、つまり最新の値のみが外部に公開されます。
  4. つまり、
  5. RxJS
は状態データの管理に適しているということでしょうか?答えは「はい」です!

まず、

Observable

自体は複数の値のプッシュ コレクションであるため、最初の条件は満たされます。 #2 番目に、dispatch action

パターンを使用して 2 番目の条件を満たすようにデータをプッシュする

observable を実装できます!ご存知のとおり、RxJS

observable

は 2 つのタイプに分類できます。 コールド観察可能: プッシュされたプロデューサー値 (

Producer

) は observable 内から取得されます。 値をいくつプッシュするか、どのような値をプッシュするかは、observable

の作成時に定義されており、変更できません。
  • プロデューサーはオブザーバー (
  • observer
  • ) と 1 対 1 の関係を持ち、ユニキャストです。 observer がサブスクライブするたびに、
  • Producer
  • はいくつかの事前定義された値を observer に順番にプッシュします。 hot observable
  • : 値をプッシュする
Producer

は、外部の observable から取得されます。 いくつの値がプッシュされるか、どの値がプッシュされるか、いつプッシュされるかは、作成時には不明です。

    Producer
  • observer
  • には 1 対多の関係、つまりマルチキャストがあります。 observer がサブスクライブするたびに、他のライブラリや言語の
  • addListener
  • と同様に、observer がオブザーバー リストに登録されます。 外部 Producer がトリガーまたは実行されると、値はすべての
  • observer
  • 、つまりすべての observer## に同時にプッシュされます。 #hot observable によってプッシュされた値を共有しました。 RxJS によって提供される
  • BehaviorSubject
は特別な

ホットオブザーバブル であり、データを外部にプッシュするためのインターフェイスを公開しますnext 関数; そして、observer に送信された最新の値を保存する「現在値」の概念があります。新しいオブザーバーがサブスクライブすると、その値はすぐに BehaviorSubject から取得されます。 これは「現在の値」を受け取ります。 これは、BehaviorSubject を使用して状態を更新し、状態の現在の値を保存することが可能であり、3 番目の条件も満たされていることを示しています。

簡単な実装次のコードを見てください:

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);
実行コード コンソールには 3 つの値が出力されます:

Console

 1
 2
 4
上記このコードは、単純な状態管理の例​​を実装するだけです。

状態の初期値: 1

実行後の状態値

plus
    : 2
  • ##toDouble
  • を実行した後の #State 値: 4
  • 実装方法は非常に簡単です。つまり、
  • 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;
        }
      }
    });

    更新状态

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

    dispatch("count", {
      type: "plus"
    })

    异步数据

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

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

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

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

    producer推送observable

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

    执行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;
      })
    );

    React视图渲染

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

    class Todos extends React.Component {
      componentWillMount() {
        todos$.subscribe(data => {
          this.setState({
            todos: data
          });
        });
      }
    }

    我们可以再优化下,利用高阶组件封装一个装饰器函数@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>
        );
      }
    }

    总结

    使用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视频教程

以上がRxJS を使用して React アプリケーションの状態を管理する方法の概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。