【Jotai】Reactの状態管理を簡単・軽量に!

React React

あなたは、Reactアプリケーションの状態管理に頭を悩ませたことはありませんか?複雑なコンポーネント階層、props drilling、そして巨大な状態ツリー...。これらの問題に直面し、「もっと簡単な方法はないのか」と思ったことがあるでしょう。

実は、そんなあなたの悩みを解決する魔法のような解決策が存在します。その名も「Jotai」。

Jotaiは、シンプルで直感的、そして驚くほど軽量な状態管理ライブラリです。本記事では、Jotaiの基本から高度な使い方まで、実践的な例を交えて詳しく解説します。この記事を読めば、あなたのReactアプリケーションの状態管理が劇的に改善されること間違いなしです!

さあ、Jotaiの魔法の世界へ飛び込んでみましょう。きっと、あなたのReact開発が今までよりもずっと楽しくなるはずです!

Jotaiとは?基本概念を理解しよう

Jotaiは、日本語で「状態」を意味する「状態(じょうたい)」から名付けられたReact用の状態管理ライブラリです。2020年にDaishi Kato氏によって開発され、そのシンプルさと柔軟性で多くの開発者から支持を得ています。

Jotaiの特徴

  1. プリミティブベース: Jotaiは「アトム」と呼ばれる最小単位の状態を基本としています。これにより、必要な状態だけを必要な場所で使用できます。
  2. 軽量: バンドルサイズが小さく、アプリケーションのパフォーマンスへの影響を最小限に抑えます。
  3. TypeScript対応: 型安全性が高く、開発時のエラー検出が容易です。
  4. React Suspenseとの相性が良い: 非同期処理との統合が簡単です。
  5. ボイラープレートの削減: 複雑な設定やアクション、リデューサーの定義が不要です。

Jotaiの基本的な仕組み

Jotaiの中心概念は「アトム(atom)」です。アトムは最小単位の状態を表し、以下のような特徴があります:

  • 読み取り可能
  • 書き込み可能(オプション)
  • 他のアトムから導出可能

アトムを使用することで、状態をコンポーネント間で簡単に共有し、更新できます。

以下は、Jotaiの基本的な使用例です:

import { atom, useAtom } from 'jotai'

// アトムの作成
const countAtom = atom(0)

function Counter() {
  // アトムの使用
  const [count, setCount] = useAtom(countAtom)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>Increment</button>
    </div>
  )
}

この例では、countAtomという名前のアトムを作成し、初期値を0に設定しています。useAtomフックを使用してこのアトムの値を読み取り、更新しています。

Jotaiの基本的な使い方

では、Jotaiの基本的な使い方を、step by stepで見ていきましょう。

Step 1: Jotaiのインストール

まず、プロジェクトにJotaiをインストールします。

npm install jotai

yarn add jotai

Step 2: アトムの作成

アトムは、atom関数を使用して作成します。

import { atom } from 'jotai'

const textAtom = atom('Hello, Jotai!')
const countAtom = atom(0)

Step 3: アトムの使用

作成したアトムは、useAtomフックを使って読み取りや更新ができます。

import { useAtom } from 'jotai'

function TextComponent() {
  const [text, setText] = useAtom(textAtom)

  return (
    <div>
      <p>{text}</p>
      <input value={text} onChange={(e) => setText(e.target.value)} />
    </div>
  )
}

function CountComponent() {
  const [count, setCount] = useAtom(countAtom)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>Increment</button>
    </div>
  )
}

Step 4: 派生アトムの作成

アトムから新しいアトムを派生させることもできます。これは、既存の状態に基づいて新しい状態を計算する場合に便利です。

const doubleCountAtom = atom((get) => get(countAtom) * 2)

function DoubleCountComponent() {
  const [doubleCount] = useAtom(doubleCountAtom)

  return <p>Double Count: {doubleCount}</p>
}

Step 5: 非同期アトムの作成

Jotaiは非同期処理もサポートしています。これは、APIからデータを取得する場合などに便利です。

const userAtom = atom(async () => {
  const response = await fetch('https://api.example.com/user')
  return response.json()
})

function UserComponent() {
  const [user] = useAtom(userAtom)

  if (user === undefined) {
    return <p>Loading...</p>
  }

  return <p>Welcome, {user.name}!</p>
}

Jotaiの高度な使い方

基本的な使い方を理解したところで、Jotaiのより高度な機能を見ていきましょう。

アトムファミリー

アトムファミリーは、動的にアトムを生成する強力な機能です。これは、リストやテーブルの各アイテムに対して個別の状態を持たせたい場合に特に有用です。

import { atomFamily } from 'jotai/utils'

const itemAtomFamily = atomFamily((id) => atom({ id, text: '', completed: false }))

function TodoItem({ id }) {
  const [item, setItem] = useAtom(itemAtomFamily(id))

  return (
    <div>
      <input
        value={item.text}
        onChange={(e) => setItem({ ...item, text: e.target.value })}
      />
      <input
        type="checkbox"
        checked={item.completed}
        onChange={(e) => setItem({ ...item, completed: e.target.checked })}
      />
    </div>
  )
}

アトムの値の永続化

アトムの値をローカルストレージに保存し、アプリケーションを再読み込みしても状態を保持することができます。

import { atom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'

const persistedCountAtom = atomWithStorage('count', 0)

function PersistedCounter() {
  const [count, setCount] = useAtom(persistedCountAtom)

  return (
    <div>
      <p>Persisted Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>Increment</button>
    </div>
  )
}

Suspenseとの統合

JotaiはReact Suspenseと相性が良く、非同期データの読み込みを簡単に扱えます。

import { Suspense } from 'react'
import { atom, useAtom } from 'jotai'

const userAtom = atom(async () => {
  const response = await fetch('https://api.example.com/user')
  return response.json()
})

function User() {
  const [user] = useAtom(userAtom)
  return <div>Welcome, {user.name}!</div>
}

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <User />
    </Suspense>
  )
}

デバッグツール

Jotaiには、開発時に役立つデバッグツールが用意されています。

import { useAtomsDebugValue } from 'jotai/devtools'

function DebugComponent() {
  useAtomsDebugValue()
  return null
}

このコンポーネントをアプリケーションに追加することで、React DevToolsでアトムの状態を確認できます。

テスト

Jotaiを使用したコンポーネントのテストは、通常のReactコンポーネントのテストと大きく変わりません。ただし、アトムの初期値を設定するためにProviderコンポーネントを使用することがあります。

import { Provider } from 'jotai'
import { render, screen } from '@testing-library/react'

test('Counter displays correct initial value', () => {
  render(
    <Provider initialValues={[[countAtom, 5]]}>
      <Counter />
    </Provider>
  )
  expect(screen.getByText('Count: 5')).toBeInTheDocument()
})

Jotaiのパフォーマンス最適化

Jotaiは設計上、優れたパフォーマンスを発揮します。しかし、大規模なアプリケーションでは、さらなる最適化が必要になる場合があります。ここでは、Jotaiを使用する際のパフォーマンス最適化のテクニックをいくつか紹介します。

細粒度のアトム設計

状態を適切に分割し、細かいアトムに分けることで、不要な再レンダリングを防ぐことができます。

// 良い例
const firstNameAtom = atom('')
const lastNameAtom = atom('')

// あまり良くない例
const userAtom = atom({ firstName: '', lastName: '' })

この方法では、firstNameだけが変更された場合に、lastNameを使用しているコンポーネントが再レンダリングされるのを防ぐことができます。

useMemo と useCallback の活用

派生アトムを作成する際、useMemoを使用することで、不要な再計算を避けることができます。

import { useMemo } from 'react'
import { atom, useAtom } from 'jotai'

const heavyComputationAtom = atom((get) => {
  const value = get(someAtom)
  return expensiveComputation(value)
})

function HeavyComponent() {
  const [result] = useAtom(heavyComputationAtom)
  const memoizedResult = useMemo(() => result, [result])

  return <div>{memoizedResult}</div>
}

同様に、useCallbackを使用して、コールバック関数を最適化することもできます。

splitAtom の使用

大きな配列や複雑なオブジェクトを扱う場合、splitAtomを使用することで、パフォーマンスを向上させることができます。

import { splitAtom } from 'jotai/utils'

const originalAtom = atom([1, 2, 3, 4, 5])
const splitAtoms = splitAtom(originalAtom)

function SplitComponent() {
  const [atoms] = useAtom(splitAtoms)
  return (
    <div>
      {atoms.map((anAtom, i) => (
        <Item key={i} atom={anAtom} />
      ))}
    </div>
  )
}

function Item({ atom }) {
  const [value, setValue] = useAtom(atom)
  return (
    <input
      value={value}
      onChange={(e) => setValue(Number(e.target.value))}
    />
  )
}

この方法では、個々の項目が変更された場合に、その項目のコンポーネントのみが再レンダリングされます。

selectAtom の利用

selectAtomを使用することで、大きなオブジェクトの一部分だけを選択して使用できます。これにより、不要な再レンダリングを減らすことができます。

import { selectAtom } from 'jotai/utils'

const userAtom = atom({ name: 'John', age: 30, email: 'john@example.com' })
const userNameAtom = selectAtom(userAtom, (user) => user.name)

function UserName() {
  const [name] = useAtom(userNameAtom)
  return <div>{name}</div>
}

この例では、userAtomの他のプロパティが変更されても、UserNameコンポーネントは再レンダリングされません。

useAtomValue と useSetAtom の活用

useAtomの代わりにuseAtomValueuseSetAtomを使用することで、さらに細かい最適化が可能です。

import { useAtomValue, useSetAtom } from 'jotai'

const countAtom = atom(0)

function ReadOnlyCounter() {
  const count = useAtomValue(countAtom)
  return <div>Count: {count}</div>
}

function IncrementButton() {
  const setCount = useSetAtom(countAtom)
  return <button onClick={() => setCount(c => c + 1)}>Increment</button>
}

この方法では、ReadOnlyCounterは値の変更時にのみ再レンダリングされ、IncrementButtonは値が変更されても再レンダリングされません。

Jotaiと他の状態管理ライブラリの比較

Jotaiは確かに優れた状態管理ライブラリですが、他の選択肢と比較してどうなのでしょうか?ここでは、Jotaiと他の人気のある状態管理ライブラリを比較してみましょう。

Jotai vs Redux

  1. 複雑さ: Jotaiは非常にシンプルで、ボイラープレートコードが少ないです。一方、Reduxはより構造化されていますが、アクション、リデューサー、セレクターなどの概念を理解する必要があります。
  2. 学習曲線: Jotaiの学習曲線は比較的緩やかで、Reactの基本を理解していれば簡単に始められます。Reduxはより深い理解が必要で、学習曲線がやや急です。
  3. パフォーマンス: 小規模から中規模のアプリケーションでは、Jotaiの方がパフォーマンスが良い傾向にあります。大規模アプリケーションでは、適切に設計されたReduxストアも高いパフォーマンスを発揮します。
  4. デバッグ: Reduxには強力なデバッグツール(Redux DevTools)があります。Jotaiもデバッグツールを提供していますが、機能はやや限定的です。

Jotai vs Recoil

  1. 概念: JotaiとRecoilは非常に似ています。どちらも「アトム」という概念を中心に設計されています。
  2. バンドルサイズ: Jotaiの方がRecoilよりもバンドルサイズが小さいです。
  3. API: Jotaiの方がやや低レベルなAPIを提供しており、より柔軟な使用が可能です。Recoilは高レベルなAPIを提供し、特定のユースケースでより簡単に使えることがあります。
  4. 安定性: Jotaiの方が安定版(1.0)をリリースしており、APIの変更が少ないです。Recoilは執筆時点でまだベータ版です。

Jotai vs MobX

  1. パラダイム: Jotaiは関数型プログラミングの原則に基づいていますが、MobXはオブジェクト指向プログラミングの原則に基づいています。
  2. 変更の追跡: MobXは自動的に変更を追跡しますが、Jotaiでは明示的に状態の更新を行います。
  3. 学習曲線: Jotaiの方が学習曲線が緩やかです。MobXは強力ですが、デコレータやobservableなどの概念を理解する必要があります。
  4. 柔軟性: Jotaiは非常に柔軟で、さまざまな使用パターンに適応できます。MobXはより意見が強く、特定の使用パターンを推奨します。

Jotaiの実践的な使用例

ここまでJotaiの基本的な使い方から高度な機能、そして他のライブラリとの比較まで見てきました。では、実際のアプリケーションでJotaiをどのように使用するのか、具体的な例を見てみましょう。

例1: Todoリストアプリケーション

まず、典型的なTodoリストアプリケーションを作成してみましょう。

import { atom, useAtom } from 'jotai'
import { atomFamily } from 'jotai/utils'

// Todoアイテムの型定義
type Todo = {
  id: number
  text: string
  completed: boolean
}

// Todoリストを管理するアトム
const todosAtom = atom<Todo[]>([])

// 個々のTodoアイテムを管理するアトムファミリー
const todoAtomFamily = atomFamily((id: number) =>
  atom((get) => get(todosAtom).find((todo) => todo.id === id))
)

// Todo追加用の関数
const addTodoAtom = atom(null, (get, set, text: string) => {
  const todos = get(todosAtom)
  const newTodo: Todo = { id: Date.now(), text, completed: false }
  set(todosAtom, [...todos, newTodo])
})

// Todoの完了状態を切り替える関数
const toggleTodoAtom = atom(null, (get, set, id: number) => {
  const todos = get(todosAtom)
  set(todosAtom, todos.map(todo =>
    todo.id === id ? { ...todo, completed: !todo.completed } : todo
  ))
})

function TodoList() {
  const [todos] = useAtom(todosAtom)
  const [, addTodo] = useAtom(addTodoAtom)
  const [newTodoText, setNewTodoText] = useState('')

  const handleAddTodo = () => {
    if (newTodoText.trim()) {
      addTodo(newTodoText)
      setNewTodoText('')
    }
  }

  return (
    <div>
      <input
        value={newTodoText}
        onChange={(e) => setNewTodoText(e.target.value)}
        placeholder="新しいTodoを入力"
      />
      <button onClick={handleAddTodo}>追加</button>
      {todos.map((todo) => (
        <TodoItem key={todo.id} id={todo.id} />
      ))}
    </div>
  )
}

function TodoItem({ id }: { id: number }) {
  const [todo] = useAtom(todoAtomFamily(id))
  const [, toggleTodo] = useAtom(toggleTodoAtom)

  if (!todo) return null

  return (
    <div>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => toggleTodo(id)}
      />
      <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
        {todo.text}
      </span>
    </div>
  )
}

この例では、JotaiのatomatomFamily、そして派生アトムを使用して、Todoリストの状態を管理しています。各Todoアイテムは個別のアトムとして管理されるため、1つのアイテムの状態が変更されても、他のアイテムは再レンダリングされません。

例2: ショッピングカートアプリケーション

次に、少し複雑なショッピングカートアプリケーションを作成してみましょう。

import { atom, useAtom } from 'jotai'
import { atomFamily, selectAtom } from 'jotai/utils'

// 商品の型定義
type Product = {
  id: number
  name: string
  price: number
}

// カートアイテムの型定義
type CartItem = {
  productId: number
  quantity: number
}

// 商品リストを管理するアトム
const productsAtom = atom<Product[]>([
  { id: 1, name: 'リンゴ', price: 100 },
  { id: 2, name: 'バナナ', price: 200 },
  { id: 3, name: 'オレンジ', price: 150 },
])

// カートを管理するアトム
const cartAtom = atom<CartItem[]>([])

// 個々のカートアイテムを管理するアトムファミリー
const cartItemAtomFamily = atomFamily((productId: number) =>
  atom((get) => get(cartAtom).find((item) => item.productId === productId))
)

// カートに商品を追加する関数
const addToCartAtom = atom(null, (get, set, productId: number) => {
  const cart = get(cartAtom)
  const existingItem = cart.find(item => item.productId === productId)
  if (existingItem) {
    set(cartAtom, cart.map(item =>
      item.productId === productId ? { ...item, quantity: item.quantity + 1 } : item
    ))
  } else {
    set(cartAtom, [...cart, { productId, quantity: 1 }])
  }
})

// カートの合計金額を計算する派生アトム
const cartTotalAtom = selectAtom(cartAtom, (cart, get) => {
  const products = get(productsAtom)
  return cart.reduce((total, item) => {
    const product = products.find(p => p.id === item.productId)
    return total + (product ? product.price * item.quantity : 0)
  }, 0)
})

function ProductList() {
  const [products] = useAtom(productsAtom)
  const [, addToCart] = useAtom(addToCartAtom)

  return (
    <div>
      <h2>商品リスト</h2>
      {products.map((product) => (
        <div key={product.id}>
          <span>{product.name} - ¥{product.price}</span>
          <button onClick={() => addToCart(product.id)}>カートに追加</button>
        </div>
      ))}
    </div>
  )
}

function CartSummary() {
  const [cart] = useAtom(cartAtom)
  const [products] = useAtom(productsAtom)
  const [total] = useAtom(cartTotalAtom)

  return (
    <div>
      <h2>カート</h2>
      {cart.map((item) => {
        const product = products.find(p => p.id === item.productId)
        return product ? (
          <div key={item.productId}>
            <span>{product.name} x {item.quantity}</span>
          </div>
        ) : null
      })}
      <div>合計: ¥{total}</div>
    </div>
  )
}

この例では、商品リスト、カート、そして合計金額をそれぞれ別のアトムで管理しています。selectAtomを使用して、カートの合計金額を計算する派生アトムを作成しています。これにより、カートの内容が変更されるたびに自動的に合計金額が再計算されます。

Jotaiの注意点と制限事項

Jotaiは非常に強力で柔軟な状態管理ライブラリですが、使用する際にいくつか注意すべき点があります。

  1. アトムの過剰使用: アトムは非常に軽量ですが、過剰に使用すると管理が難しくなる可能性があります。適切な粒度でアトムを設計することが重要です。
  2. 非同期アトムの扱い: 非同期アトムを使用する際は、Suspenseとエラー境界を適切に設定する必要があります。これを怠ると、アプリケーションが予期せぬ動作をする可能性があります。
  3. デバッグの複雑さ: Jotaiのデバッグツールは改善されつつありますが、まだReduxほど強力ではありません。複雑なアプリケーションでのデバッグには注意が必要です。
  4. SSRとの統合: サーバーサイドレンダリング(SSR)との統合は可能ですが、初期状態の管理に注意が必要です。
  5. 学習リソースの制限: Jotaiは比較的新しいライブラリであるため、学習リソースや情報が他の確立されたライブラリと比べて限られている可能性があります。

まとめ

Jotaiは、Reactアプリケーションの状態管理を非常にシンプルかつ効率的に行うことができるライブラリです。その特徴は以下のとおりです:

  1. シンプルさ: 複雑な設定やボイラープレートコードが不要で、直感的に使用できます。
  2. 柔軟性: アトムを基本単位とすることで、細かい粒度での状態管理が可能です。
  3. パフォーマンス: 必要な部分のみを更新する設計により、高いパフォーマンスを実現しています。
  4. TypeScript対応: 型安全性が高く、開発時のエラー検出が容易です。

Jotaiを使うことで、複雑な状態管理の問題を解決し、よりメンテナンス可能で効率的なReactアプリケーションを構築することができます。特に、中小規模のプロジェクトや、既存のプロジェクトに段階的に導入する場合に適しています。

しかし、どのツールも万能ではありません。プロジェクトの規模、チームの経験、既存のコードベースなど、さまざまな要因を考慮して、Jotaiが自分のプロジェクトに適しているかどうかを慎重に判断する必要があります。

Jotaiの今後の展望

Jotaiは比較的新しいライブラリですが、急速に成長し、進化を続けています。以下は、Jotaiの今後の展望と期待される発展について考察します。

  1. コミュニティの成長: Jotaiのコミュニティは着実に成長しており、今後さらに多くの開発者がJotaiを採用することが予想されます。これにより、サードパーティ製のツールやライブラリ、学習リソースが増加する可能性があります。
  2. パフォーマンスの向上: Jotaiの開発チームは常にパフォーマンスの向上に取り組んでいます。将来的には、さらに最適化された実装や新しいパフォーマンス最適化テクニックが導入される可能性があります。
  3. API拡張: ユーザーフィードバックや新しいユースケースに基づいて、APIが拡張される可能性があります。ただし、Jotaiの設計思想であるシンプルさは維持されるでしょう。
  4. デバッグツールの改善: 現在のデバッグツールは基本的な機能を提供していますが、今後さらに強化される可能性があります。時間の経過とともに、より高度で使いやすいデバッグツールが開発されるかもしれません。
  5. フレームワーク統合: 現在、JotaiはReactに特化していますが、将来的には他のフレームワーク(例:Vue、Svelte)との統合も検討される可能性があります。
  6. サーバーサイドレンダリング(SSR)のサポート強化: SSRのサポートは既に存在しますが、今後さらに改善され、より使いやすくなる可能性があります。

Jotaiを使いこなすためのヒント

最後に、Jotaiを効果的に使用するためのいくつかのヒントを紹介します。

  1. アトムの適切な設計: アトムは小さく保ち、必要に応じて派生アトムを使用して複雑な状態を管理します。
  2. パフォーマンスプロファイリング: React DevToolsを使用して、コンポーネントの再レンダリングを監視し、必要に応じて最適化します。
  3. TypeScriptの活用: Jotaiは TypeScriptと相性が良いです。型を適切に使用することで、バグの早期発見や開発効率の向上につながります。
  4. テストの重要性: Jotaiを使用したコンポーネントやロジックのテストを書くことを忘れずに。テストは長期的なメンテナンス性を高めます。
  5. ドキュメンテーション: アトムの役割や相互作用を明確にドキュメント化しておくことで、チームでの開発がスムーズになります。
  6. 段階的な導入: 既存のプロジェクトにJotaiを導入する場合は、一度にすべてを置き換えるのではなく、段階的に導入することをおすすめします。
  7. コミュニティの活用: Jotaiの公式ドキュメントやGitHubのイシューを定期的にチェックし、最新の情報やベストプラクティスを把握しておくことが重要です。

Jotaiを使った実践的なチュートリアル

ここで、Jotaiを使った簡単なチュートリアルを通して、実際の使用感を体験してみましょう。このチュートリアルでは、シンプルな通貨換算アプリケーションを作成します。

ステップ1: プロジェクトのセットアップ

まず、新しいReactプロジェクトを作成し、Jotaiをインストールします。

npx create-react-app currency-converter --template typescript
cd currency-converter
npm install jotai

ステップ2: アトムの定義

src/atoms.tsファイルを作成し、以下のコードを追加します:

import { atom } from 'jotai'

export const amountAtom = atom(1)
export const fromCurrencyAtom = atom('USD')
export const toCurrencyAtom = atom('EUR')

// 為替レートは通常APIから取得しますが、ここでは簡単のため固定値を使用します
const exchangeRates = {
  USD: { EUR: 0.85, JPY: 110 },
  EUR: { USD: 1.18, JPY: 130 },
  JPY: { USD: 0.0091, EUR: 0.0077 }
}

export const resultAtom = atom((get) => {
  const amount = get(amountAtom)
  const from = get(fromCurrencyAtom)
  const to = get(toCurrencyAtom)
  
  if (from === to) return amount
  
  // @ts-ignore (型エラーを無視します。実際のアプリでは適切に型を定義してください)
  const rate = exchangeRates[from][to]
  return amount * rate
})

ステップ3: コンポーネントの作成

src/App.tsxファイルを以下のように更新します:

import React from 'react'
import { useAtom } from 'jotai'
import { amountAtom, fromCurrencyAtom, toCurrencyAtom, resultAtom } from './atoms'

const CurrencySelector: React.FC<{
  atom: typeof fromCurrencyAtom,
  label: string
}> = ({ atom, label }) => {
  const [currency, setCurrency] = useAtom(atom)
  return (
    <div>
      <label>{label}: </label>
      <select value={currency} onChange={(e) => setCurrency(e.target.value)}>
        <option value="USD">USD</option>
        <option value="EUR">EUR</option>
        <option value="JPY">JPY</option>
      </select>
    </div>
  )
}

function App() {
  const [amount, setAmount] = useAtom(amountAtom)
  const [result] = useAtom(resultAtom)

  return (
    <div className="App">
      <h1>通貨換算アプリ</h1>
      <div>
        <label>金額: </label>
        <input
          type="number"
          value={amount}
          onChange={(e) => setAmount(Number(e.target.value))}
        />
      </div>
      <CurrencySelector atom={fromCurrencyAtom} label="From" />
      <CurrencySelector atom={toCurrencyAtom} label="To" />
      <div>
        <strong>結果: {result.toFixed(2)}</strong>
      </div>
    </div>
  )
}

export default App

ステップ4: アプリケーションの実行

以下のコマンドでアプリケーションを起動します:

npm start

これで、Jotaiを使用した簡単な通貨換算アプリケーションが完成しました!各入力フィールドは個別のアトムとリンクされており、結果はresultAtomという派生アトムで計算されています。このアプリケーションでは、Jotaiの特徴である以下の点が活かされています:

  1. シンプルな状態管理
  2. 派生アトムによる自動計算
  3. コンポーネント間での状態の共有

結論

Jotaiは、Reactアプリケーションの状態管理を大幅に簡素化し、開発者の生産性を向上させる強力なツールです。その軽量性、柔軟性、そして直感的なAPIは、多くの開発者にとって魅力的な選択肢となっています。

特に、以下のような場合にJotaiの使用を検討することをおすすめします:

  1. 小規模から中規模のReactプロジェクト
  2. パフォーマンスが重要なアプリケーション
  3. TypeScriptを使用したプロジェクト
  4. 段階的に状態管理を導入したい既存のプロジェクト

しかし、どの技術を選択する場合でも、プロジェクトの要件、チームの経験、既存のコードベースなどを総合的に考慮することが重要です。Jotaiは多くの場合に素晴らしい選択肢となりますが、常にプロジェクトのニーズに最も適したツールを選ぶようにしましょう。

最後に、Jotaiは急速に発展しているライブラリですので、公式ドキュメントや関連するリソースを定期的にチェックし、最新の情報やベストプラクティスを把握しておくことをおすすめします。Jotaiを使いこなすことで、よりクリーンで保守性の高いReactアプリケーションを構築できるでしょう。

Happy coding with Jotai! 🎉

参考リンク

  1. Jotai 公式ドキュメント
  2. Jotai GitHub リポジトリ
  3. React 公式ドキュメント

コメント

タイトルとURLをコピーしました