仕事でReact用ステート管理ライブラリーRecoilを使ってみました。
現在作成中のアプリでは、サーバーから取得したデータの一覧画面があります、 そこでデータをクリックすると詳細画面が表示されます。
課題は、詳細画面から一覧画面に戻ったさい、再度サーバーからデータ一を取得しないで再表示したいのです。
一覧データをキャッシュしておくのも良いかもしれませんが複雑になりますよね。そこで思いついたのは一覧データをグローバルなステート管理に置けば良いのでは?です。
Recoilを使おう
そこで、思いついたのがRecoilです。今回は、Redux(Toolkit)のような複雑なステート管理ではなく、シンプルでグローバルなステート管理が必要だったのでRecoil使ってみました。
説明用アプリ
説明用に、いつもこのブログで使っているジャンケン・アプリに少し機能追加しました。
- ① Selectタグで画面を選択できるようにしました
- ② ゲーム0ならジャンケンが表示され、ゲーム1なら③のその他 ゲームが表示されます
const App: React.FC = () => {
const [page, setPage] = useState(0);
return (
<>
<select onChange={e => setPage(Number(e.target.value))} > // ← ①
<option value={0}>ゲーム 0</option>
<option value={1}>ゲーム 1</option>
</select>
{page === 0 ? <Jyanken/> : <Other />} // ← ②
</>
)
}
const Jyanken: React.FC = () => {
const [scores, setScrores] = useState<ScoreType[]>([])
const pon = (human: Te) => {
const computer: Te = Math.floor(Math.random() * 3)
const judgment: Jjudgment = (computer - human + 3) % 3
const score = {human: human, computer: computer, judgment: judgment}
setScrores([score, ...scores])
}
return (
<>
<h1>じゃんけん ポン!</h1>
<JyankenBox actionPon={te => pon(te)} />
<ScoreBox scores={scores} />
</>
)
}
const Other: React.FC = () => { // ← ③
return (
<h1>その他 ゲーム</h1>
)
}
export default App;
Reactアプリの動きをGIFアニメにしてみました
ゲーム0でジャンケンを行い、ゲーム1に切り替え、再びゲーム0に戻すと最初のジャンケン結果は消えています。
ジャンケン結果はReactのステートで管理しているので、ゲーム1に切り替えた瞬間Jyankenコンポーネントがメモリー上から解放されてしまい、再びゲーム0に切り替えたさい新たなJyankenコンポーネントが生成されるからです。
説明用アプリをRecoilに置き換える
npm install recoil
でRecoilをインストールしindex.tsx
に<RecoilRoot>
を追加します- ① Recoilから関数をインポート
- ② Recoilでは複数のステートを管理できます。
atom
関数は1つのステート管理を作る関数で、それらの識別子をkey:
に指定し、初期値をdefault:
に指定します - ③ Reactの
useState
同等の機能はuseRecoilState
になります。
以上でscores
がグローバルなステートになりました。
import { atom, useRecoilState } from 'recoil' // ← ①
const App: React.FC = () => {
const [page, setPage] = useState(0);
return (
<>
<br/><br/>
<select onChange={e => setPage(Number(e.target.value))} >
<option value={0}>ゲーム 0</option>
<option value={1}>ゲーム 1</option>
</select>
{page === 0 ? <Jyanken/> : <Other />}
</>
)
}
const jyankenState = atom<ScoreType[]>({ // ← ②
key: 'jyanken',
default: []
})
const Jyanken: React.FC = () => {
const [scores, setScrores] = useRecoilState(jyankenState) // ← ③
const pon = (human: Te) => {
const computer: Te = Math.floor(Math.random() * 3)
const judgment: Jjudgment = (computer - human + 3) % 3
const score = {human: human, computer: computer, judgment: judgment}
setScrores([score, ...scores])
}
return (
<>
<h1>じゃんけん ポン!</h1>
<JyankenBox actionPon={te => pon(te)} />
<ScoreBox scores={scores} />
</>
)
}
const Other: React.FC = () => {
return (
<h1>その他 ゲーム</h1>
)
}
export default App;
Recoil版アプリの動きをGIFアニメにしてみました
ゲーム0でジャンケンを行い、ゲーム1に切り替え、再びゲーム0に戻すと最初のジャンケン結果が表示されます!
まとめ
Recoilを使うとReact標準のステート管理useState
を、コンポーネントのライフサイクル(生成・解放)とは独立したグローバルなステート管理に簡単に移行できます。 素晴らし〜🥰