2021/07/08
はじめに
最近,自分の時間には React を使って開発することが多い.
1年前くらいに初めて触れてから,いくつかの簡単な Web アプリを作って Firebase を用いて公開したりしている.
その過程で,React Context API や React Redux を試してみたりしていた.
ちなみに,本ブログも React (Next.js)によって構築している(2021/07/08 現在).
recoil とは?
Facebook が開発・公開してる OSS の一つで,react 開発者に簡潔なグローバルなステート管理を提供するライブラリである.
文法も非常に簡潔で,必要なところで必要な分だけ,変数へのアクセスを提供してくれるため,開発をスムーズに勧める助けとなる.
「必要なところに必要な分だけ」というのが個人的には気に入っていて,それについては後述する.
どのような人におすすめか?
大体以下のような人におすすめ
- react hooks を普段から使っている
- ステート管理にどれを使うか悩んでいる
- dispatch が複雑で困っている
- グローバルなステート管理に問題を抱えている
使い方を紹介していく
ここでは,npx create-react-app my-app --template typescript
で初期化されたアプリに対し,簡単なカウンターアプリを作ってみる.
1. インストール
$ npm install recoil
2. RecoilRoot で囲む
RecoilRoot
という名称の理由は分からないが,よくある<***Provider>
のようなもの.
特にこだわりがなければ,広い範囲を囲めるようにindex.tsx
やApp.tsx
などに組み込むのがよいと思っている.
以下のように書く.
import React from 'react';
import ReactDOM from 'react-dom';
import { RecoilRoot } from 'recoil';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
3. countState を作る
個人的には,/src/store/countState.ts
のようなパスで作ることをおすすめする.
中身は以下のようにする.好みによってexport default
にしても良いと思う.
import { atom } from 'recoil';
export const countState = atom({
key: "countState",
default: 0,
})
4. 関数コンポーネント内でステート利用
useRecoilState
は,ステートの値の参照および更新を行うことができる.
import React from 'react';
import { useRecoilState } from 'recoil';
import { countState } from './store/countState';
const Counter:React.FC<{}> = () => {
const [count, setCount] = useRecoilState<number>(countState);
return (
<>
<button onClick={() => setCount(count + 1)}>increment</button>
<span>{count}</span>
<button onClick={() => setCount(count - 1)}>decrement</button>
</>
)
}
export default Counter;
5. 関数コンポーネントを利用
import React from 'react';
import logo from './logo.svg';
import './App.css';
import Counter from './Counter';
const App:React.FC<{}> = () => {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<Counter />
</header>
</div>
);
}
export default App;
ステートへの限定的アクセス
グローバルなステートに対し,各コンポーネントは,「値の参照だけ」や「値の更新だけ」を行いたい場合もある.
そんな時でも,recoil では容易に要望を満たせる.
値の参照だけ
useRecoilValue
を使うと,値の参照だけをすることができる.
import React from 'react';
import { useRecoilValue } from 'recoil';
import { countState } from './store/countState';
const CounterViewer:React.FC<{}> = () => {
const count = useRecoilValue<number>(countState);
return (
<>
<span>{count}</span>
</>
)
}
export default CounterViewer;
値の更新だけ
useSetRecoilState
を使うと,値の更新だけをすることができる.
ちなみに,以下の例では,setCount(4)
のようにすると,count
の値は4
になる.
import React from 'react';
import { useSetRecoilState } from 'recoil';
import { countState } from './store/countState';
const Counter:React.FC<{}> = () => {
const setCount = useSetRecoilState<number>(countState);
return (
<>
<button onClick={() => setCount(oldcount => oldcount + 1)}>increment</button>
</>
)
}
export default Counter;
所感(よいところ)
まず第一に,import
の段階で,どのステートを使うのか分かる.
次に,関数コンポーネントの最初に Hooks と一緒に宣言するuse***<T>(***State)
の段階で,各ステートに対して,何を行うのかが分かる.具体的には,「値を参照するのか?」「値を更新するのか?」である.
最後に好みの問題だが,簡単な状態管理にdispatch()
のアクションを都度用意する必要がなく,開発が加速する.
おわりに
私は今後も recoil を使っていく.
また,現状はまだSelector
は使ったことがないが,きちんと使い方を知っておきたいなと思っている.