【初心者向け】React状態管理ライブラリ Jotaiを解説

こんにちは、サイオステクノロジーの遠藤です。

Reactでアプリを作っていると、「状態管理ってどうすればいいの?」と悩むことがありますよね。たとえば、useState を利用していると、コンポーネントの階層が深くなってきたときにpropsのバケツリレーで複雑になりうまく管理できなくなることがあります。

そんなときに便利なのが Jotai というライブラリです! Jotaiを使うと、シンプルな書き方で状態を管理でき、複雑なアプリでも扱いやすくなります。

この記事では、Jotaiの基本的な使い方を初心者向けにわかりやすく解説します。「Reactの状態管理をもっと簡単にしたい!」という方は、ぜひ最後まで読んでみてください!

Jotaiとは?

Jotaiは、Reactの状態管理をシンプルにするライブラリです。「Atom(アトム)」と呼ばれる単位で状態を管理し、それらを組み合わせることでアプリの状態を作ります。

Jotaiの特徴は、必要な部分だけを効率よく更新すること。ReactのContextを使った状態管理では、不要な再レンダリングが発生しがちですが、Jotaiは依存するAtomだけを更新するため、パフォーマンスが最適化されます。そのため、メモ化(memoization)を意識する必要が少なく、スムーズに開発できます。

また、小規模なアプリから大規模なTypeScriptアプリまで対応でき、公式のユーティリティや拡張機能も豊富に用意されています。シンプルなuseStateの代わりに使うことも、大規模なプロジェクトで本格的に活用することもできる柔軟なライブラリです。

公式サイト : https://jotai.org/

Core API

JotaiのAPIはとてもシンプルで、必要最小限の機能だけが提供されています。基本的には「atom」「useAtom」「Store」「Provider」という4つのCore APIで状態管理が完結します。

atom

Jotaiのatomは、アプリの状態を定義するための基本的な単位です。Reactの useState に似ていますが、グローバルに管理できるのが特徴です。

atomは「状態の設定(atom config)」を作るだけで、実際に値を保持しているわけではありません。値はStoreと呼ばれる仕組みに保存されます。そのため、atom自体は変更できず、常に不変(immutable)なオブジェクトとして扱われます。

atomの作成方法

基本的なatomは atom 関数を使って作成します。初期値を渡せば、その値を持つatomが作成されます。

import { atom } from 'jotai'

const priceAtom = atom(10) // 数値の状態
const messageAtom = atom('hello') // 文字列の状態
const productAtom = atom({ id: 12, name: 'good stuff' }) // オブジェクトの状態


useAtom

useAtom は、atomの値を読み取ったり更新したりするためのフック です。Reactの useState に似た使い方ができ、atomの値と更新関数を返します。

const [value, setValue] = useAtom(anAtom)

この value は現在のatomの値で、setValue を使って新しい値に更新できます。

useAtomの基本的な使い方

まず、atomを作成します。

import { atom, useAtom } from 'jotai'

const countAtom = atom(0) // 初期値 0 の atom

次に、コンポーネント内で useAtom を使って、この countAtom の値を取得・更新します。

const Counter = () => {
  const [count, setCount] = useAtom(countAtom)

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  )
}


このように、 useAtom を使えば、コンポーネント内で簡単にグローバルな状態を管理できます。

注意点: useAtom内でatomを直接作らない

useAtom(atom(0)) のように、コンポーネント内で毎回新しいatomを作ると、レンダリングのたびに異なるatomが作られてしまい、無限ループが発生する ことがあります。

const [count] = useAtom(atom(0)) // ❌ 毎回新しいatomを作るのでNG

代わりに、コンポーネントの外でatomを定義する ようにしましょう。

const countAtom = atom(0) // ✅ 外で定義すればOK
const [count] = = useAtom(doubleCountAtom) // ✅ 正しく動作

Store

Store は、atomの値を管理するための独立した状態コンテナです。通常、Jotaiはデフォルトの Store を使用するため、特に意識しなくても状態を管理できます。しかし、createStore を使ってカスタム Store を作成すると、複数の状態ツリーを独立して管理 できるようになります。

Storeの作成と使用

import { atom, createStore } from 'jotai'

const myStore = createStore() // 新しいStoreを作成

const countAtom = atom(0)

// Storeを直接操作
myStore.set(countAtom, 1) // countAtom の値を 1 に更新
console.log(myStore.get(countAtom)) // 1

// 値の変更を監視
const unsubscribe = myStore.sub(countAtom, () => {
  console.log('countAtomが変更されました:', myStore.get(countAtom))
})

Providerとは?

Provider は、JotaiのStoreを特定のコンポーネントツリーに適用するためのコンポーネント です。
通常、Jotaiはデフォルトの Store を使うので Provider なしでも動作しますが、以下のような場合に Provider を使うと便利です。

Providerを使うメリット

  1. 異なる状態を持つ複数のコンポーネントツリーを作れる
    • 例えば、2つの Provider を使うことで、同じ atom を異なる状態として管理できます。
  2. 初期値を適用できる
    • Providerstore に初期値を設定して、コンポーネントごとに異なるデータを扱えます。
  3. Provider の再マウントで状態をリセットできる
    • Provider を再マウントすると、その配下のatomの状態をクリアできます。

Providerの使い方

デフォルトのProvider(特に指定しない場合)

import { atom, useAtom, Provider } from 'jotai'

const countAtom = atom(0)

const Counter = () => {
  const [count, setCount] = useAtom(countAtom)

  return (
    <div>
      <p>カウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  )
}

const App = () => (
  <Provider>
    <Counter />
  </Provider>
)

この場合、Provider を使わなくてもデフォルトのStoreが適用されます。

カスタムStoreをProviderに適用

作成した StoreProvider に適用すると、独立した状態管理 が可能になります。

const myStore = createStore()

const Root = () => (
  <Provider store={myStore}>
    <App />
  </Provider>
)

こうすることで、myStore を使用した状態管理が App 以下のコンポーネントに適用されます。

異なるProviderで独立した状態を持たせる

異なる Provider を使うと、同じ atom でも別々の状態として扱えます。

const Counter = () => {
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      <p>カウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  )
}

const App = () => (
  <div>
    <Provider>
      <h2>Provider 1</h2>
      <Counter />
    </Provider>
    <Provider>
      <h2>Provider 2</h2>
      <Counter />
    </Provider>
  </div>
)

この例では、それぞれの Provider が独立した Store を持っているため、1つのカウンターを更新してももう1つには影響しません。

Tips : Jotaiで状態をローカルストレージに保存する方法

CoreAPIの機能ではありませんが、、atomWithStorage を使うことで、状態を localStoragesessionStorage に簡単に保存できます。これにより、ユーザーの設定やデータを次回のセッションでも保持できます。

atomWithStorage の基本

atomWithStorage は Jotai の jotai/utils モジュールに含まれており、指定したキーで localStorage または sessionStorage と同期されます。ページの再読み込み後も、保存された値が自動的に取得されます。

例: テーマの状態を保存する

以下のコードでは、atomWithStorage を使ってテーマ(dark or light)を localStorage に保存し、ページをリロードしても選択したテーマが保持されるようにしています。

import { useAtom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';

// 'dark' というキーでローカルストレージに保存するAtom
const theme = atomWithStorage('dark', false);

export default function Page() {
  const [appTheme, setAppTheme] = useAtom(theme);

  const handleClick = () => setAppTheme(!appTheme);

  return (
    <div className={appTheme ? 'dark' : 'light'}>
      <h1>テーマ切り替え</h1>
      <button onClick={handleClick}>
        {appTheme ? 'DARK' : 'LIGHT'}
      </button>
    </div>
  );
}

まとめ

本記事では、Jotaiの基本的な使い方便利な機能 について解説しました。Jotaiは useState のように直感的に使え、シンプルな記述でグローバルな状態管理ができる のが特徴です。

また、createStore()Provider を活用することで、画面ごとに異なる状態を管理したり、状態をリセットしたりすることも可能です。Reduxのような複雑なセットアップが不要で、初心者でも扱いやすいライブラリ なので、「もっと簡単に状態を管理したい!」という方におすすめです。Jotaiを使って、Reactアプリの状態管理をシンプルにしてみましょう! 🎉

ではまた~

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です