0
0

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

Last updated at Posted at 2024-08-23

Recoilとは?

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

Reduxとの違いは?

Reduxのメリット デメリット

メリット

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

デメリット

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

Recoilのメリット デメリット

メリット

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

デメリット

  • アプリケーションが大規模になったときに複雑になる。

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

実装方法

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

image.png

インストール

npm install recoil

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

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にて管理する。

①の設定

import { atom } from "recoil";

export const inputTitleState = atom<string>({
	key: "inputTitleState",
	default: "",
});

上記のようにRecoilでは、atomという関数を使って、状態管理したいオブジェクトを定義する。
keyは一意の名前。 defaultは初期の状態となる。

②の設定

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の参照と更新

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のように参照用変数と更新用関数を定義できる。
(コメントアウト部分は、個々に定義する場合の記述方法。)

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

定義したらuseStateと同じように使うだけ。(コード抜粋)

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

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

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

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について調べていた途中に、メンテが停止したことを知りました。
せっかく便利さを知って、今後使ってみようと思ったのにとても残念です。。。。。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0