【初めてのjotai】Reactの状態管理で噂のjotaiを使ってみた。

タイトルにもある通り、Reactの状態管理でjotaiというライブラリを使ってみました。
私はこれまでcontextを使って状態管理をしてきましたが、コードが冗長になったり、いちいち長いreducerを作ったりするのが面倒でした。
recoilを使って状態管理をしている人も多いかと思いますが、他の選択肢としてjotaiがあったので使ってみることにしました。

本記事においては、jotaiの簡単な使い方を記載します。

# jotaiとは
+ Reactの状態管理ライブラリ
+ recoilのようなatomicなアプローチでの状態管理が可能
+ contextと比較すると、無駄な再レンダリングが走らないのでメモ化を意識する必要が少ない
+ useStateみたいな感覚で利用でき、処理が簡潔

# インストール方法
```terminal
# npm
npm i jotai

# yarn
yarn add jotai

# pnpm
pnpm add jotai
```

# 簡単な使い方
よく例として出てくるcounterを作成してみます。

まず、atomを作成します。
非常に簡単で、atom()やcreateAtom()を用いて状態管理を行うatomを作成します。
```tsx
import { atom } from 'jotai'

// 初期値を0にしたatomを作成
const counterAtom = atom(0)
```

次にこのatomを利用するコンポーネントを作成します。
useContextみたいなノリでuseAtomが利用できます。
この時、useStateのように、監視する変数と値を更新する関数が返却されます。
```tsx
import { useAtom } from 'jotai'
const Counter = () => {
    // 上記で作成したatomを引数に入れてuseAtomを呼び出す
    const [count, setCount] = useAtom(textAtom)

    return (
        <button onClick={() => setCount(count+1)}>インクリメント</button>
    );
};
```
counterの結果を表示するコンポーネントを作成します。

```tsx
import { useAtom } from 'jotai'
const Display = () => {
    // 上記で作成したatomを引数に入れてuseAtomを呼び出す
    const [count] = useAtom(textAtom)

    return (
        <div>{count}</div>
    );
};
```

上記を組み合わせるとボタンをクリックする度に表示用のcountが変化されていくはずです。

```tsx
const Sample = () => {    
    return(
        <Display />
        <Counter />
    )
}
```
jotaiを使うとatomicに状態管理が可能ということがわかります。
また、非常に簡単に実装できます。

# メニューの開閉をjotaiでやってみた
より具体的な例でjotaiを使ってみます。
例としてはメニューの開閉を採用しました。

ここでは以下のコンポーネントを用意することにします。

| コンポーネント | 補足 |
|:-:|:-:|
|App.tsx |一番上位のコンポーネント   |
|Top.tsx   |TOPページを想定   |
|Header.tsx   |TOPページ内に入れるヘッダー   |
|Menu.tsx|HeaderのMenuアイコンを押すと表示されるMenu|
|MenuState.ts|Menuを表示するか否かの状態を管理する|

※インポート部分は省略

```tsx:App.tsx
const App = () => {
  // メニューの開閉フラグを取得する
  const [openMenu] = useAtom(openMenuAtom);
  
  return (
    <div className={classes.container}>
      // メニューフラグがtrueの時、Menuコンポーネントを表示
      { openMenu && (
          <Menu></Menu>
      ) : (
      <BrowserRouter>
        <AdminAppProvider>
          <Routes>
            <Route path={'/top'} element={<Top />} />
          </Routes>
        </AdminAppProvider>
      </BrowserRouter>
      )}
    </div>
  );
};

export default App;
```

```tsx:Top.tsx
const Top = () => {
    return(
        <div>
            <Header />
            <div>コンテンツ</div>
        </div>
    )
}

export default Top;
```

```tsx:Header.tsx
const Header = () => {
    const [, setOpenMenu] = useAtom(openMenuAtom);
    return (
        <div>
            <div>タイトル</div>
            <button onClick={setOpenMenu(true)}><button>
        </div>
    )
}

export default Header;
```



```tsx:Menu.tsx
const Menu = () => {
    const [, setOpenMenu] = useAtom(openMenuAtom);
    return (
        <div>
            <div onClick={() => setOpenMenu(false)}>閉じる</div>
            // ハンターハンター解説サイトを想定（関係ない）
            <div>
                <div>トップへ</div>
                <div>なぜハンター試験を受けるのか</div>
                <div>水見式のやり方</div>
            </div>
        <div>
    )
}

export default Menu;
```

```tsx:MenuState.ts
// atomを使って、Menuの開閉フラグをグローバルに宣言
export const openMenuAtom = atom(false);
```



上記のように、コンポーネントを跨ってグローバルに状態管理ができます。
今回はビギナーな内容でしたが、他にも便利なものがあるので勉強していきます。