【Recoil入門】Atom、useRecoilStateの使い方 

## Recoilとは
Recoilは2020年5月にFacebookによってリリースされたReactの状態管理ライブラリです。

React Hooksの`useState()`はコンポーネント内でのstate（状態）を管理するのに対し、Recoilはアプリケーション全体でのstateを管理します。
(Reduxとの違いは[こちら](https://ics.media/entry/210224/)の記事に詳しく記載されてました。)

## Recoilのインストール
Recoilをインストールするには次のコマンドを実行します。
```Bash
$ npm install recoil
```
または
```Bash
$ yarn add recoil
```

## RecoilRoot
Recoilを使用するためにはコンポーネントを`RecoilRoot`で囲む必要があります。
ルートコンポーネントであるApp.jsxに配置するのが最適。
ルートコンポーネントに配置することで全ての子孫コンポーネントでRecoilが利用できます。

```jsx:src/App.jsx
import { RecoilRoot } from 'recoil'
import { TextInput } from './components/TextInput'
import { CharacterCount } from './components/CharacterCount'

function App() {
  return(
    <RecoilRoot>
      <TextInput />
      <CharacterCount />
    </RecoilRoot>
  )
}
```

## Atom
`Atom`はStateを管理するためのデータストア。
Reduxはアプリケーション全体で状態管理を行うストアが一つなのに対し、Recoilは`Atom`単位で一つ一つの状態管理を行う。

#### Atomの作成
`key`にアプリケーション全体で一意なキー、`default`に状態管理したい値の初期値を設定します。
状態管理したい値一つごとに`Atom`を一つ作っていく。

ここでは入力したテキストを保持する`Atom`を作成します。

```js:src/atoms/textState.js
import { atom } from 'recoil'

export const textState = atom({
  key: 'textState'  // 一意のキー
  default: ''       // 初期値
})
```

## useRecoilState()
stateの取得・更新を行う場合、`useRecoilState()`を使用します。
`useRecoilState()`の引数には使用したいstateを渡します。
戻り値は最初の要素にstateの値、２つ目の要素にstateの値を更新するセッター関数であるタプルを返します(React Hooksの`useState()`と同じ)。
**※stateの値を読み取るコンポーネントは、stateが更新されると自動的にレンダリングされます。**

#### Atomの状態の取得・更新
作成した`Atom`から値を取得して出力します。
また、テキストフィールドに値を入力すると、`Atom`の値を更新します。
```jsx:src/components/TextInput.jsx
import { useRecoilState } from 'recoil'
import { textState } from '../atoms/textState'

export const TextInput = () => {
  // const [状態変数, 状態を変更するための関数] = useRecoilState(使用するstate)
  const [text, setText] = useRecoilState(textState)
  
  // 入力値でAtomを更新
  const handleChange = (e) => {
    setText(e.target.value)
  }

  return(
    <>
      <input value="text" onChange={handleChange} />
      <br />
      出力: {text}
    </>
  )
}
```

## Selector
`Selector`は`Atom`にもとづく派生state。
`Atom`の値を何らかの計算や加工した結果を返します。

#### Selectorの作成
`key`にアプリケーション全体で一意なキーを設定。
`get`はGetRecoilValue型の`get`を引数に持ち、`Atom`の値を加工して返す関数を設定します。
(stateの値を何らかの計算や加工をして更新することもできる。今回は値の取得の`get`のみ説明。)

ここでは先ほど作成した`textState`から値を取り出し、入力したテキストの文字数を計算して返すSelectorを作成します。

```jsx:src/selectors/charCountState.js
import { selector } from 'recoil'
import { textState } from '../atoms/textState'

const charCountState = selector({
  key: 'charCountState',
  //Atomの値を加工して返す関数を設定
  get: ({get}) => {
    //const 状態変数 = get(Atomのkey)
    const text = get(textState)
    //加工した値を返す
    return text.length
  }
})
```

## useRecoilValue
stateの値の取得のみを行う場合、`useRecoilValue()`を使用します(読み取り専用)。
`useRecoilValue()`は引数に使用するstateの`key`を渡します。
戻り値はstateの値を返します。
**※stateの値を読み取るコンポーネントは、stateが更新されると自動的にレンダリングされます。**

#### Selectorから値を取得
作成した`Selector`から値を取り出して、入力したテキストの文字数を出力します。
```jsx:src/components/CharacterCount.jsx
import { useRecoilValue } from 'recoil'
import { charCountState } from '../selectors/charCountState'

export const CharacterCount.jsx = () => {
  // const 状態変数 = useRecoilValue(使用するstate)
  const count = useRecoilValue(charCountState)
  
  return <>文字数：　{count}</>
}
```

以上がRecoilの基本的な使い方になります。