Recoil最低限 Next編 （2021年9月）


NextでRecoilおよびPersist使ってみる。
Create-React-App編は[こちら](https://qiita.com/zaburo/items/e28be44f6b98e36b38c7)をどうぞ。

## やりたいこと・作るもの

ページを移動しても値が維持（共有）され、ページをリロードしても値が（保持したければ）保持されるという機能の検証。

![スクリーンショット 2021-09-05 9.22.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/7f1c7deb-4446-3e1c-c5e8-5e6575016231.png "スクリーンショット 2021-09-05 9.22.30.png")



## 準備

### プロジェクトの作成

create-next-appを利用してプロジェクトを作成。

```bash
npx create-next-app next-recoil-test
cd next-recoil-test
```

recoilをインストール。

```bash
npm install recoil
```

ページが移動しても値が維持されることを確認したいのでpages以下にabout.jsを作成しておきます。

```bash
touch pages/about.js
```

recoilはatomを作成し、値を共有するのでatom定義用のファイルを用意しておきます。
comopnents以下にatoms.jsを作りました。

```bash
mkdir components
touch components/atoms.js
```

## 実装

では実装していきます。

### _app.js


recoilでは値を共有したい範囲をRecoilRootで囲います。
通常はアプリ全体で共有するので_app.jsで定義します。


```js:_app.js
import '../styles/globals.css'
import { RecoilRoot } from "recoil"; //追加

const MyApp = ({ Component, pageProps }) => {
  return (
    <RecoilRoot>
      <Component {...pageProps} />
    </RecoilRoot>
  );
}

export default MyApp;
```

### atoms.js

atoms.jsの記述。ここではcountとuserという値を共有する値としたいと思います。

```js:atoms.js
import { atom } from "recoil";

//count
export const countState = atom({
    key: "count",
    default: 0
});

//user
export const userState = atom({
    key: "user",
    default: {
        name: "hoge",
        age: 11
    }
});
```

### index.js

index.js(Home)にcountとuser情報を表示および編集する機能を実装してみます。


```js:index.js
import Link from "next/link";
import { useRecoilState } from "recoil";
import { countState, userState } from "../components/atoms";

const Home = () => {

  //atomの値の操作を定義（read,write)
  const [count, setCount] = useRecoilState(countState);
  const [user, setUser] = useRecoilState(userState);

  //count increment処理
  const increment = c => {
    return c + 1;
  }

  //userのageをカウントアップ（機能としては意味無し）
  const updateUser = u => {
    return { ...u, ...{ age: u.age + 1 } };
  }

  return (
    <>
      <h1>Home</h1>
      <div>
        <p>count:{count}</p>
        <button onClick={() => setCount(increment)}>count increment</button>
        <hr />
        <p>user.name:{user.name}</p>
        <p>user.age:{user.age}</p>
        <button onClick={() => setUser(updateUser)}>age increment</button>
      </div>
      <hr />
      <div>
        <Link href="/about"><a>About</a></Link>
      </div>
    </>
  );
}

export default Home;
```

### about.js

about.jsでは読み取りだけしてみたいと思います。


```js:about.js
import Link from "next/link";
import { useRecoilValue } from "recoil";
import { countState, userState } from "../components/atoms";

const About = () => {

    //atomの値の操作を定義（read only)
    const count = useRecoilValue(countState);
    const user = useRecoilValue(userState);

    return (
        <>
            <h1>About</h1>
            <div>
                <p>count:{count}</p>
                <p>user.name:{user.name}</p>
                <p>user.age:{user.age}</p>
            </div>
            <hr/>
            <div>
                <Link href="/"><a>Home</a></Link>
            </div>
        </>
    );
}

export default About;
```

## 動作確認

完成したら動作を確認してみます。

```bash
npm run dev
```

## 値の永続化（persist）

実アプリでデータの永続化は必須となります。
ここではuser情報だけを継続化したいと思います。redux-persistに比べかなり簡単です！
atoms.jsを少しいじるだけ。

### モジュールのインストール

```bash
npm install recoil-persist
```

### atoms.jsを改修

数行追加するだけ。便利。簡単。

```js:atoms.js
import { atom } from "recoil";
import { recoilPersist } from "recoil-persist";

const { persistAtom } = recoilPersist();

//count
export const countState = atom({
    key: "count",
    default: 0
});

//user
export const userState = atom({
    key: "user",
    default: {
        name: "hoge",
        age: 11
    },
    effects_UNSTABLE: [persistAtom] //追加
});
```