Recoilについて学びながら記事を書いていた途中にメンテ停止を知った件。

## Recoilとは？
RecoilはReactの状態管理ライブラリ。
Reduxと同じような役割。

https://recoiljs.org/

## Reduxとの違いは？

### Reduxのメリット デメリット

#### メリット
* アプリケーション全体で状態を管理するため、わかりやすい。
* コンポーネント間のデータの受け渡しが不要になる。

#### デメリット
* Reducer, Action, Middlewareの定義など、コード量が多くなるため、小規模アプリケーションでは大掛かりすぎる。
* 小さな単位の状態管理もアプリケーション全体で管理する必要がある。
* 難しい。

### Recoilのメリット デメリット

#### メリット
* アプリケーション全体ではなく、指定したコンポーネント間で状態管理ができる。
* useStateの進化系のような感覚で使用できる。
* コンポーネント間のデータの受け渡しが不要になる。

#### デメリット
*  アプリケーションが大規模になったときに複雑になる。
<br>

以上を踏まえ、小規模アプリケーションの場合、Recoilの方が実装しやすいのでは！？と思い、以下で実践。


## 実装方法
今回は、inputから追加されたタスクをリスト表示し、個数を表示するアプリをRecoilを使用して作成。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/144c14dc-e3af-919a-99b0-c24159136f25.png)


### インストール

```bash
npm install recoil
```

### Recoil Rootで状態管理にアクセスしたいコンポーネントを囲む

```tsx
import AddTask from "./components/AddTask";
import InputTask from "./components/InputTask";
import "./App.css";
import { RecoilRoot } from "recoil";

function App() {
	return (
		<RecoilRoot>
			<div className="App">
				<InputTask />
				<AddTask />
			</div>
		</RecoilRoot>
	);
}

export default App;
```

上記の場合、Recoilで状態管理したデータにアクセスできるのは、InputTaskコンポーネントとAddTaskコンポーネントのみとなる。

### Atomの設定

今回は、①inputに入力された値の状態 「inputTitleStatet」と、②追加されたタスクの状態「addTitleState」をRecoilにて管理する。


#### ①の設定
```tsx
import { atom } from "recoil";

export const inputTitleState = atom<string>({
	key: "inputTitleState",
	default: "",
});
```
上記のようにRecoilでは、atomという関数を使って、状態管理したいオブジェクトを定義する。
keyは一意の名前。　defaultは初期の状態となる。

#### ②の設定
```tsx
import { atom, selector } from "recoil";
import { Task } from "../types/Task";

export const addTitleState = atom<Array<Task>>({
	key: "addTitleState",
	default: [],
});

export const addTitleStateLength = selector<number>({
	key: "addTitleStateLength",
	get: ({ get }) => {
		const addTitleNumber: Array<Task> = get(addTitleState);
		return addTitleNumber?.length || 0;
	},
});
```
②は追加されたタスクを管理するため、Task型（別途定義）の配列をデフォルト値に指定。

addTitleStateLengthに使用されている、selector関数は、atomのデータを使用して処理を行う関数を定義する際に使用される。
getはatomのデータを取得している。

addTitleStateLengthは、タスクの数の状態を管理するための関数となる。

 ### Atomの参照と更新
```tsx
import "./InputTask.css";
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import { inputTitleState } from "../states/inputTitleState";
import { addTitleState } from "../states/addTitleState";
import { useCallback } from "react";

const getKey = () => {
	return Math.random().toString(32).substring(2);
};

const InputTask = () => {
	// const inputTitle = useRecoilValue(inputTitleState);
	// const setInputTitle = useSetRecoilState(inputTitleState);
	const [inputTitle, setInputTitle] = useRecoilState(inputTitleState);
	const [addTitle, setAddTitle] = useRecoilState(addTitleState);

	const onChange = useCallback(
		(e: React.ChangeEvent<HTMLInputElement>) => {
			setInputTitle(e.target.value);
		},
		[inputTitle]
	);

	const handleClick = () => {
		setAddTitle([...addTitle, { id: getKey(), title: inputTitle }]);
		setInputTitle("");
	};

	return (
		<div className="inputField">
			<input type="text" className="inputTitle" onChange={onChange} value={inputTitle} />
			<button type="button" className="addButton" onClick={handleClick}>
				追加
			</button>
		</div>
	);
};

export default InputTask;
```

以下コード（抜粋）により、useStateのように参照用変数と更新用関数を定義できる。
（コメントアウト部分は、個々に定義する場合の記述方法。）
```tsx
	// const inputTitle = useRecoilValue(inputTitleState);
	// const setInputTitle = useSetRecoilState(inputTitleState);
	const [inputTitle, setInputTitle] = useRecoilState(inputTitleState);
	const [addTitle, setAddTitle] = useRecoilState(addTitleState);
 ```

 定義したらuseStateと同じように使うだけ。（コード抜粋）
 ```tsx
 	const onChange = useCallback(
		(e: React.ChangeEvent<HTMLInputElement>) => {
			setInputTitle(e.target.value);
		},
		[inputTitle]
	);

	const handleClick = () => {
		setAddTitle([...addTitle, { id: getKey(), title: inputTitle }]);
		setInputTitle("");
	};
 ```

 表示部分も同じ。参照用変数をJSX内に組み込むだけ。

```tsx
import "./AddTask.css";
import { useRecoilValue } from "recoil";
import { addTitleState, addTitleStateLength } from "../states/addTitleState";

const AddTask = () => {
	const addTitle = useRecoilValue(addTitleState);
	const addTitleLength = useRecoilValue(addTitleStateLength);
	return (
		<div className="taskField">
			<div>タスクの数：{addTitleLength}個</div>
			<ul>
				{addTitle.map((task) => (
					<li key={task.id}>{task.title}</li>
				))}
			</ul>
		</div>
	);
};

export default AddTask;
```

## 最後に

以上、Recoilの基礎的な使い方でした。
Reduxと比べコード量も減り、参照・更新に関しては、useState感覚で行えるのでとても楽だと感じました。

だがしかし。。。

記事を書きながらRecoilについて調べていた途中に、メンテが停止したことを知りました。
せっかく便利さを知って、今後使ってみようと思ったのにとても残念です。。。。。