👻

React状態管理ライブラリ Jotai のコンセプトとは #JotaiFriends

2022/01/15に公開

Jotai was born to solve extra re-render issue in React. Extra re-render is a render process that produces the same UI result, with which users won't see any differences.

Jotaiは、Reactの余分な再レンダリングの問題(extra re-render issue)を解決するために生まれました。余分な再レンダリングとは、同じUI結果を生成するレンダー処理で、ユーザーには何の違いも見えません。

よく話題になるのはContextをグローバルなステート管理に用いた時の再レンダリング問題です。Contextから提供されているステートを使っている(useContext()している)全てのコンポーネントがステートの更新によって再レンダリングされてしまいます。

To tackle this issue naively with React context (useContext + useState), one would probably require many contexts and face some issues.

Reactのコンテキスト(useContext + useState)で素朴にこの問題に取り組むには、おそらく多くのコンテキストが必要になり、いくつかの問題に直面するでしょう。

React公式で言及されているようにサイトのライトモード/ダークモード、ログイン状態のように頻繁に変わらないものへのContextの利用は想定されていますが、複雑で手に負えない数のContextをアプリ全体のステート管理として使う時にはReact的には想定外な利用ですし、問題があるよね、という話です。代表的な問題点であろう2点が挙げられています。

  • Provider hell: It's likely that your root component has many context providers, which is technically okay, and sometimes desirable to provide context in different subtree.
  • プロバイダ地獄: ルートコンポーネントが多くのコンテキストプロバイダを持っている可能性があります。技術的には問題ありませんが、異なるサブツリーでコンテキストを提供することが望ましい場合もあります。
  • Dynamic addition/deletion: Adding a new context at runtime is not very nice, because you need to add a new provider and its children will be re-mounted.
  • 動的な追加と削除: 実行時に新しいコンテキストを追加すると、新しいプロバイダを追加する必要があり、プロバイダ以下の子コンポーネント全てが再マウントされるため、あまりいいものではありません。

Jōtai作者である@dai_shiさんはこれまでに多くのライブラリを開発されてますが(代表作はこちら)、Contextの問題点に取り組んだものが以下のuse-context-selectorになります。

Traditionally, a top-down solution to this is to use selector interface. The use-context-selector library is one example. The issue with this approach is the selector function needs to return referentially equal values to prevent re-renders and often requires some memoization technique.

伝統的に、これに対するトップダウンの解決策は、セレクタ・インターフェースを使うことです。use-context-selectorライブラリはその一例です。この方法の問題点は、セレクタ関数が再レンダリングを防ぐために参照的に等しい値を返す必要があり、しばしば何らかのメモ化技術を必要とすることです。

セレクタ関数とは、例えば以下の state => state.firstName です。

import { useContextSelector } from 'use-context-selector';

const firstName = useContextSelector(PersonContext, state => state.firstName);

Jotai takes a bottom-up approach with atomic model, inspired by Recoil. One can build state combining atoms and renders are optimized based on atom dependency. This avoids requiring the memoization technique.

Jotaiは、Recoilにヒントを得て、アトミックモデルによるボトムアップアプローチを採用しています。Atomを組み合わせてステートを構築し、atomの依存関係に基づいてレンダリングが最適化されます。このため、メモ化のテクニックは必要ありません。

Recoilインスパイアということもあり、ユーザーに受け入れてもらえるようにAPIの見た目が似ているのだと思います。RecoilのAPIと見比べてみるとわかるかと思いますが、Jotaiのほうがよりシンプルに使うことができます。
ちなみに今更(?)ですが、JotaiはContextベースなステート管理ライブラリです。

Jotai has two principles.

  • Primitive: Its basic interface is pretty much like useState.
  • Flexible: Derived atoms can combine other atoms and also allow useReducer style with side effects.
    Jotai's core API is minimalistic and allows building various utils based on it.
    Check out comparison doc to see some differences with other libraries.

Jotaiは2つの原則を持っています。

  • 原始的であること: 基本的なインターフェースは、useStateとほぼ同じです。
  • フレキシブルであること: 派生atomは他のatomを組み合わせることができ、また副作用のあるuseReducerスタイルも可能です。
    JotaiのコアAPIはミニマルであり、これをベースに様々なユーティリティを構築することができます。
    他のライブラリとの違いについては、比較ドキュメントをご覧ください。

Coreは3つのAPIのみがexportされています。(https://github.com/pmndrs/jotai/blob/v1.5.0/src/index.ts )ステートを定義するatom関数, コンポーネントで利用するためのuseAtom関数、コンポーネントサブツリーへステートを提供するためのProviderコンポーネント、です。
「原始的でありフレキシブルであること」、この指針で設計されたcore API3つで何でも出来てしまいます。利用頻度が多かったりユースケースとしてあったら便利な関数がutilsから提供されています。
フレキシブルさを感じることができる点として、他ライブラリとのインテグレーションも挙げられます。他のステート管理ライブラリと連携するステート管理ライブラリなんて見たことがあるでしょうか。(話が脱線してきたのでこのあたりにて)

Jotaiのコンセプトとは

  • React Contextの余分な再レンダリング問題の解決を目指している
  • APIはアトミックモデルによるボトムアップアプローチが採用され、シンプルでミニマルな仕様になっている
  • フレキシブルさを持ち、使い方を開発者に委ねている

Jotaiの紹介特集について

この記事はJotai FriendsによるJotai紹介特集記事の1つです。記事一覧はこちらからどうぞ。

Jotai Friendsとは

いちJotaiファンとして、エンジニアの皆さんにもっとJotaiを知ってもらって使ってもらいたい、そんな思いから立ち上げたのがJotai Friendsです。

https://jotaifriends.dev/

現在まだまだ準備中ですが今後ともよろしくお願いします!
(ご興味持っていただけた方は是非jotaifriends.devにてEメールアドレスのご登録をお願いします🙏)

Jotai Friends

Discussion