contact

blog-MainImage

Kabe-Log

2022-02-03

2022-2-4

React状態管理ライブラリ valtioとRecoilでコード比較

frontend,

React.js,

Library

最近、状態管理ライブラリではvaltioを使ってるのですが、久しぶりにRecoilも触ってみたいと思いコード比較してみました。ちなみに、Recoilは何ヶ月か前に触ったっきりです。

そもそも、valtio、Recoilとは

Valtio、Recoilはどちらもreactの状態管理ライブラリになります。状態をオブジェクトごとに分割して(一つ一つをAtomという)管理できるのが特徴です。対してReduxはストアと呼ばれる場所で状態を一まとまりで管理します。

コード比較

それぞれ同じ機能を作って、簡単にコード比較してみました。 こちらが実際に作ったものになります。フォームの値が表示されていく簡単なものです。

valtio:Recoil.png

GitHub: https://github.com/K-Keita/Valtio-Recoil_chatDemo

なるべく、同じように記述するようにしています。 本来は同じサイトで状態管理ライブラリを複数インストールし扱うのはよくないです。 スタイルはtailwind.css、フォームはreact-hook-formを使用しています。

Recoil

import type { SubmitHandler } from "react-hook-form"; import { useForm } from "react-hook-form"; import { atom, selector, useRecoilState } from "recoil"; import { Chat } from "src/components/chat"; //Atomを使用して、状態を保存 export const arrState = atom<{ value: string; createdAt: string }[]>({ key: "arrState", default: [ { value: "test1", createdAt: "1/1 11:11" }, { value: "test2", createdAt: "2/2 22:22" }, ], }); export const RecoilComponent = (): JSX.Element => { const { register, handleSubmit, reset } = useForm<{ text: string }>(); const onSubmit: SubmitHandler<{ text: string }> = (data) => { if (data.text === "") { return false; } addText(data.text); reset(); }; // useRecoilStateで状態を取得 const [arr, setArr] = useRecoilState(arrState); // コンポーネント内部に記述 const deleteText = (i: number) => { const newArr = [...arr].filter((x, index) => { return index !== i; }); setArr(newArr); }; const addText = (text: string) => { const d = new Date(); const createdAt = `${ d.getMonth() + 1 }/${d.getDate()} ${d.getHours()}:${d.getMinutes()}`; const newArr = [...arr, { value: text, createdAt: createdAt }]; setArr(newArr); }; return ( <div className="p-5 md:w-1/2"> <p className="text-2xl">Recoil</p> {arr.map((value, i) => { return <Chat key={i} items={value} i={i} delete={deleteText} />; })} <form onSubmit={handleSubmit(onSubmit)}> <input {...register("text")} className="block p-1 my-3 w-full bg-white bg-opacity-10 border border-gray-500" /> <button className="block py-1 px-3 ml-auto text-white bg-blue-500 hover:bg-opacity-90" onSubmit={handleSubmit(onSubmit)} > 送信 </button> </form> </div> ); };

Atomを使って、状態を保存します。Atomが状態管理の単位になります。Keyは状態保存の識別子であり、一意である必要があります。

useRecoilState()で状態を共有できます。 記述がuseStateと同じなので、hooksを使い慣れている人にとって馴染みやすいのかなと思いました。 既視感がありますね笑 

valtio

import type { SubmitHandler } from "react-hook-form"; import { useForm } from "react-hook-form"; import { Chat } from "src/components/chat"; import { proxy, useSnapshot } from "valtio"; // proxyで状態を管理 export const state = proxy<{ arr: { value: string; createdAt: string }[] }>({ arr: [ { value: "test1", createdAt: "1/1 11:11" }, { value: "test2", createdAt: "2/2 22:22" }, ], }); // コンポーネントの外部で記述、破壊的メソッドを使える const deleteText = (i: number) => { state.arr.splice(i, 1); }; const addText = (text: string) => { const d = new Date(); const createdAt = `${ d.getMonth() + 1 }/${d.getDate()} ${d.getHours()}:${d.getMinutes()}`; state.arr.push({ value: text, createdAt: createdAt }); }; export const ValtioComponent = (): JSX.Element => { const { register, handleSubmit, reset } = useForm<{ text: string }>(); const onSubmit: SubmitHandler<{ text: string }> = (data) => { if (data.text === "") { return false; } addText(data.text); reset(); }; // useSnapshotで状態を取得 const { arr } = useSnapshot(state); return ( <div className="p-5 md:w-1/2"> <p className="text-2xl">valtio</p> {arr.map((value, i) => { return <Chat key={i} items={value} i={i} delete={deleteText} />; })} <form onSubmit={handleSubmit(onSubmit)}> <input {...register("text")} className="block p-1 my-3 w-full bg-white bg-opacity-10 border border-gray-500" /> <button className="block py-1 px-3 ml-auto text-white bg-blue-500 hover:bg-opacity-90" onSubmit={handleSubmit(onSubmit)} > 送信 </button> </form> </div> ); };

proxyを使用して、状態管理したいオブジェクトをラッピングし、useSnapshotで値を共有します。 valtioでは、push、spliceなど、破壊的なメソッドを使用できるのが特徴です。 Valtioに関する記事は、他でも書いているのでこちらをみてくれたら嬉しいです。

別の記事:valtioを使用し、Reactの外で状態管理を行う

それぞれの違い

1番の違いは、valtioの方はコンポーネントの外部で記述し、Recoilの方はコンポーネントの内部で記述する点です。 つまり、valtioはreactの外、Recoilはreactの中で状態を管理します。reactの外で管理できる一つのメリットは別のライブラリに置き換えたくなった時に移行が簡易的な点です。逆にRecoilはreactに依存しているので、基本的に移行する際は、新しいライブラリが必要になりますね。

valtioはコンポーネント内部の記述が減るので、関数ごとにファイルを分ければ、コードがスッキリし可読性が向上しそうです。Recoilは、前述した通りhooksと記述方法が似ているので、初めてでも導入しやすいと思います。

Recoilのselector

Recoilのselectorの機能は、色々と応用が効いて便利そうです。

SelectorはAtomのデータを操作して返すことができる機能です。Atomが更新されれば、Selectorも更新されます。本来はselectorで状態をとってきますが、上記のコードのように操作せずにそのまま取得したい場合、Atomだけでとってこれます。

// selectorの記述 export const countState = selector({ key: "countState", //stateの値を操作した値を返す get: ({ get }) => { // get()の引数にAtomを指定し、取得 const countState = get(state); // 配列の個数を返す return countState.length; }, });

useRecoilValue()でselectorの値を取得

//操作した値を共有 const count = useRecoilValue(countState); // count=現在のstateのlength

まとめ

今回使用した他にも、valtioと開発元が同じjotaiなどが、状態管理ライブラリにあります。また、以前オンラインサロンの講座で学んだのですが、SWRを使ってグローバルに状態管理することもできます。 種類が多く、どれを採用するのがベストプラクティスなのか迷います。それぞれの特徴を活かした開発ができるよう、力をつけていく必要がありますね。 今回の結論、reactは楽しいです笑。

search

recommended

AWS資格 SAPとSOAを取得したので、対策や受験時の感想について
2022-05-23AWS資格 SAPとSOAを取得したので、対策や受験時の感想について
実務経験一年の転職活動(エンジニア生活:2月)
2022-03-15実務経験一年の転職活動(エンジニア生活:2月)
2022年は、フルスタックエンジニアに(エンジニア生活:1月)
2022-02-072022年は、フルスタックエンジニアに(エンジニア生活:1月)
「AWSエンジニア入門講座――学習ロードマップで体系的に学ぶ」を読んだ感想
2022-01-29「AWSエンジニア入門講座――学習ロードマップで体系的に学ぶ」を読んだ感想
エンジニア転職した一年の振り返り
2022-01-04エンジニア転職した一年の振り返り
Remixと朝活(エンジニア生活:11月)
2021-12-02Remixと朝活(エンジニア生活:11月)

contact