リアクティブReact (no pun intended)

2021/07/26に公開

Reactはリアクティブではない

Svelte 3: Rethinking reactivity

React + RxJS = Reactive React

RxJSなどが代表的な実装であるObservableを使ってReactをリアクティブにする
Hook APIを使うと簡単

export function useObservable<T>(observable: Rx.Observable<T>, initialValue: T) {
  const [value, render] = React.useState(initialValue);
  React.useEffect(() => {
    const subscription = observable.subscribe(render);
    return () => {
      subscription.unsubscribe();
    };
  }, [observable, initialValue]);
  return value;
}

使用例(タイマー)

const Timer: React.VFC<{ timer$: Rx.Observable<string> }> = ({ timer$ }) => {
  const val = useObservable(timer$, null);

  return <div>{val === null ? "loading..." : val}</div>;
};

function App() {
  const simpleClock$ =
    Rx.interval(1000)
      .pipe(Rx.map((x) => `${x}秒経過`));
  return (
    <div>
      <h1>Hello, Reactive React!</h1>
      <Timer timer$={simpleClock$} />
    </div>
  );
}

考察

(以下執筆・考察中)

利点1. オプトインしやすさ

Hookでお手軽に使用できる
※既存のアプリケーションに、後から必要な部分にだけ導入することができる

利点2. JavaScriptネイティブな構文

JavaScriptのifArray.prototype.mapをそのまま扱うことができる

一方でSvelteのリアクティブ性はコンパイラが実現しているため、拡張性に乏しいと予想される(言語の進化=コンパイラの進化)
※分岐のために#if、反復のために#eachなど専用の構文が用意されている
Vueも同様にv-ifv-forディレクティブが専用に用意されていて、この点では筋が悪い

TODO: 本当に?

利点3. VDOMの欠点を補う

ObservableがVDOMの差分判定回数を軽減するはず

TODO: 具体的事例の提示

利点4. パフォーマンス

Observableの実装にもよるが、ストリームの依存関係を動的に構築できるはずであり、
コンパイルタイムに静的な依存グラフを作成するSvelteよりも優れた結果を出すユースケースがあり得る

TODO: 本当に?

その他考察

  • 状態管理の方法(Reduxとの親和性)
  • エラーハンドリング
  • Rx.BehaviorSubjectの利用
  • そもそもObservableで差分管理をするならばVDOM不要では?
GitHubで編集を提案

Discussion