👻

React状態管理ライブラリ Jotai での別ライブラリ連携 #JotaiFriends

2022/01/23に公開約4,100字

Jotai入門がまだの方はこちらからぜひ!

https://zenn.dev/tell_y/articles/7a5bd147d34ec2

はじめに

別ライブラリとの連携と聞くと、どういうこと?となるかと思います。ドキュメントのIntegrationsの中を見ると、ImmerやらXState、Reduxなどがあります。まさかReduxなど、別の状態管理ライブラリが登場することに戸惑う方もいることでしょう。
この記事では、なぜJotaiはそれらのライブラリと連携できるのか、その理由は、という点で見て頂ければなと思います。

Immer

ReactとImmerの連携は珍しくもないので驚きは少ないかと思います。(知らない方向け:ImmerはMutableな書き方でImmutableを実現してくれるライブラリです。マサカリ飛んできそうで怖い説明だ)
公式のReact+Immerの紹介はこちらをどうぞ。

https://immerjs.github.io/immer/example-setstate#usestate--immer

atomWithImmerでatomを作ります。useAtomから渡されるupdate関数がImmerのproduceを使って渡されるので(c) => (c = c + 1))とかけます。(src/immer/atomWithImmer)

import { useAtom } from 'jotai'
import { atomWithImmer } from 'jotai/immer'

const countAtom = atomWithImmer(0)

const Controls = () => {
  const [, setCount] = useAtom(countAtom)
  const inc = () => setCount((c) => (c = c + 1))
  return <button onClick={inc}>+1</button>
}

他にもatom(...)withImmer()atomWithImmer()で作ったatomのようにしたり、atom(...)を使う時にuseImmerAtomで使ったり出来ます。

https://jotai.org/docs/integrations/immer

Immerの公式ドキュメント

https://immerjs.github.io/immer/

React Query

React Queryの全ての機能をJotaiと共に使える、とのことです。中身を見てみると、atom(new QueryClient())してました。確かにできそう。
以下はドキュメントに記載されているサンプルです。

import { useAtom } from 'jotai'
import { atomWithQuery } from 'jotai/query'

const idAtom = atom(1)
const userAtom = atomWithQuery((get) => ({
  queryKey: ['users', get(idAtom)],
  queryFn: async ({ queryKey: [, id] }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    return res.json()
  },
}))

const UserData = () => {
  const [data] = useAtom(userAtom)
  return <div>{JSON.stringify(data)}</div>
}

<QueryClientProvider>でwrapする必要も、コンポーネント内でuseQuery()を使う必要も無いようです。全てJotai側が面倒を見てくれるので上記のようにJotaiの世界でReact Queryの恩恵を受けられます。JotaiはKey-lessで使えますが、React QueryがKeyを必要とするのでそこは少し残念ポイントでしょうか。React Queryを使っていればさほど問題はないですね。

https://jotai.org/docs/integrations/query

React Queryの公式ドキュメント

https://react-query.tanstack.com/

Redux

さぁ、今回一番のハテナが来ました。Reduxとの連携です。
ここで思い出してみます、JotaiはContextベースで作られておりReactの世界の中で状態を扱います。Reduxはというと、Reactの外に状態を持っています。(そういえば、Reduxのドキュメントの冒頭、Reactが出てこない説明だった気がします。ここです。React学びはじめの頃、戸惑った思い出・・・)
なるほど、Reactの中と外を繋げられるということですね。JotaiとRedux、両方から値を変更することが出来るようです。
以下はドキュメントに記載されているサンプルです。
store.dispatch({ type: 'INC' })でも変更可能、ということですね。

import { useAtom } from 'jotai'
import { atomWithStore } from 'jotai/redux'
import { createStore } from 'redux'

const initialState = { count: 0 }
const reducer = (state = initialState, action: { type: 'INC' }) => {
  if (action.type === 'INC') {
    return { ...state, count: state.count + 1 }
  }
  return state
}
const store = createStore(reducer)
const storeAtom = atomWithStore(store)

const Counter: React.FC = () => {
  const [state, dispatch] = useAtom(storeAtom)

  return (
    <>
      count: {state.count}
      <button onClick={() => dispatch({ type: 'INC' })}>button</button>
    </>
  )
}

https://jotai.org/docs/integrations/redux

Reduxの公式ドキュメント

https://redux.js.org/

おわりに

いかがでしたか?ハテナの解消に少しでも役立ちましたでしょうか・・・
Immer、React Query、Reduxの3つだけを見てみましたが、各ライブラリの役割をうまくJotaiに組み込んだり連携して実現できていることがわかりました。

Reduxと同じく、Reactの外の世界に状態をもつValtioやZustandも連携できます。その他、XStateは自由すぎるJotaiを整理してくれる役割を担ってくれるでしょう。GraphQLのクライアントライブラリであるURQLとの連携もあります。Apolloはありませんが、コアメンテナーの一人がjotai-apolloを用意してくれています。

連携できるライブラリの多さが、Jotaiをより面白いと思わせてくれます。もし公式が提供していなくても、Jotai with ◯◯ を自作する機会があるかも知れません。その時は既存のライブラリ連携のコードが参考になりますね。

そういえば、この記事で一旦はJotai紹介特集が終わりになります。
何かしらのお役に立っていたら幸いです。Jotai好きになった方、一緒に盛り上げていきましょう!

Jotaiの紹介特集について

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

Jotai Friendsとは

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

https://jotaifriends.dev/

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

Discussion

ログインするとコメントできます