-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jotai #193
Comments
Recoilにインスパイアされている。 Recoilとの違い
|
インストール
|
アトムimport { atom, useAtom } from 'jotai';
const countAtom = atom(0);
const App = () => {
const [count, setCount] = useAtom(countAtom);
return (
<p>{count}</p>
);
}; アトムからアトムを導出するconst countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);
const App = () => {
const [count, setCount] = useAtom(doubleCountAtom);
return (
<p>{count}</p>
);
} 複数のアトムからアトムを導出const count1 = atom(1)
const count2 = atom(2)
const count3 = atom(3)
const sum = atom((get) => get(count1) + get(count2) + get(count3)) |
コンセプトJotaiは、Reactの余分な再レンダリングの問題を解決するために生まれました。余分な再レンダリングとは、同じUI結果を生成するレンダリング処理で、ユーザーには何の違いも見えません。 Reactのコンテキスト(useContext + useState)で素朴にこの問題に取り組もうとすると、おそらく多くのコンテキストが必要になり、いくつかの問題に直面することになるでしょう。
従来、これに対するトップダウン的な解決策として、セレクタ・インターフェースを用いる方法がありました。use-context-selectorライブラリはその一例です。この方法の問題点は、セレクタ関数が再レンダリングを防ぐために参照的に等しい値を返す必要があり、多くの場合、何らかのメモ化技術が必要になることです。 Jotaiは、Recoilにインスパイアされたアトミックモデルによるボトムアップアプローチを採用しています。アトムを組み合わせて状態を構築し、アトムの依存性に基づいてレンダリングが最適化されます。これにより、メモ化技術を必要としません。 Jotaiには2つの理念があります。
JotaiのコアAPIはミニマルであり、これをベースに様々なユーティリティを構築することが可能です。 他のライブラリとの違いを見るには、比較ドキュメントをご覧ください。 |
プリミティブJotaiにおける状態は、atomの集合体です。atomは状態の一部分です。ReactのuseStateとは異なり、atomは特定のコンポーネントに縛られることはありません。では、atomの定義と使い方をみていきましょう。 atomatomというエクスポートされた関数がありますが、これはatom configを作成するためのものです。これは単なる定義で、値を保持しないので「config」と呼んでいます。文脈的に明確な場合は、単に「atom」と呼ぶこともあります。 import { atom } from 'jotai'
const priceAtom = atom(10)
const messageAtom = atom('hello')
const productAtom = atom({ id: 12, name: 'good stuff' }) また、導出atomを作ることも可能です。3つのパターンを用意しています。
導出atomを作成するには、読み込み関数とオプションの書き込み関数を渡します。 const readOnlyAtom = atom((get) => get(priceAtom) * 2)
const writeOnlyAtom = atom(
null, // 第一引数にはnullを渡す
(get, set, update) => {
// updateは、このatomを更新するために受け取る任意の値
set(priceAtom, get(priceAtom) - update.discount)
}
)
const readWriteAtom = atom(
(get) => get(priceAtom) * 2,
(get, set, newPrice) => {
set(priceAtom, newPrice / 2)
// 同時にいくつでもアトムを設定することができる
}
) 読み込み関数の 書き込み関数の 書き込み関数の atom configはどこでも作成可能ですが、参照一致が重要です。また、動的に作成することもできます。render関数でatomを作成するには、安定した参照を得るために useMemo または useRef が必要です。useMemoかuseRefを使うか迷ったら、useMemoを使いましょう。 const Component = ({ value }) => {
const valueAtom = useMemo(() => atom({ value }), [value])
// ...
} useAtomuseAtomフックは、状態にあるatom値を読み込むためのものです。状態は、atom configとatom値のWeakMapとして見ることができます。 useAtom関数は、ReactのuseStateと同様に、atom値と更新関数をタプルとして返します。引数としてatom()で作成したatom configを受け取ります。 初期状態では、状態には値が格納されていません。useAtomによりatomが初めて使用されたとき、初期値がステートに格納されます。atomが導出atomの場合は、読み込み関数が実行され、初期値が計算されます。atomが使用されなくなったとき、つまりatomを使用しているコンポーネントがすべてアンマウントされ、atom構成が存在しなくなったとき、状態の値はガベージコレクションされます。 const [value, updateValue] = useAtom(anAtom) updateValueは引数を1つだけ取り、atomのwrite関数の第3引数に渡されます。動作は書き込み関数がどのように実装されるかに完全に依存します。 ProviderProviderとは、コンポーネントのサブツリーに対して状態を提供するものです。複数のサブツリーに対して複数のProviderを使用することができ、入れ子にすることも可能です。これは、通常のReact Contextと同じように動作します。 Providerが存在しないツリーでatomが使用された場合、デフォルトの状態が使用されます。これはいわゆるProvider-lessモードです。 プロバイダーがいくつかの点で便利です。
const SubTree = () => (
<Provider>
<Child />
</Provider>
) |
AsyncJotaiでは非同期サポートは第一級です。React Suspenseをフルに活用しています。 技術的には、React.lazy以外のSuspenseの使い方はReact 17ではまだ未サポート/未ドキュメントの状態です。もしブロックされているようなら、guides/no-suspenseをチェックしてみてください。 Suspense非同期atomを使用するには、コンポーネントツリーをで囲む必要があります。がある場合、少なくとも1つのはの中に配置されます。 const App = () => (
<Provider>
<Suspense fallback="Loading...">
<Layout />
</Suspense>
</Provider>
) コンポーネントツリーでより多くのを持つことは可能です。 atomの非同期読み込みatomの読み込み関数は、Promiseを返すことができます。Promiseが達成されると、一時停止して再レンダリングします。 最も重要なことは、useAtomは解決された値しか返さないということです。 const countAtom = atom(1)
const asyncCountAtom = atom(async (get) => get(countAtom) * 2)
// 読み込み関数はPromiseを返す
const Component = () => {
const [num] = useAtom(asyncCountAtom)
// num は数値であることが保証されている
} atomは、読み取り関数が非同期であるだけでなく、その依存関係の1つ以上が非同期である場合に非同期となります。 const anotherAtom = atom((get) => get(asyncCountAtom) / 2)
// このatomはPromiseを返さないが、
// `asyncCountAtom`が非同期なので、非同期読み出しatomとなる。 |
比較Zustandとの違い名前Jotaiは日本語で「状態」を意味します。Zustandはドイツ語で「状態」を意味します。 類似性JotaiはRecoilに近い。ZustandはReduxに近い。 ステートが存在する場所JotaiのステートはReactのコンポーネントツリーの中にあります。ZustandのステートはReactの外側のストアにあります。 ステートの構成方法Jotaiのステートはatomからなる(ボトムアップ)。Zustandのステートは1つのオブジェクト(つまりトップダウン)。 技術的な違い大きな違いは、ステートモデルです。Zustandは基本的に1つのストアです(複数のストアを作ることもできますが、分離されています)。Jotaiはプリミティブなアトムで、それを合成します。その意味では、プログラミングのメンタルモデルの問題ですね。 いつ、どれを使うか
Recoilとの違い(免責事項:筆者はRecoilにあまり詳しくありません。偏りがあり、正確でない可能性があります)。 開発者
基本情報
技術的な違い
いつ、どれを使うか
|
Jotai 1.6.0
|
https://jotai.org/
The text was updated successfully, but these errors were encountered: