Recoilとは
- グローバルステートを管理するFacebookが開発しているライブラリ
使い方
-
npm install recoil
でRecoilをインストール - Reduxでいう
<provider>
のようにして<RecoilRoot>
で囲む
ReactDOM.render(
<RecoilRoot>
<App/>
</RecoilRoot>,
document.getElementById('root')
);
-
atom
とuseRecoilState
をインポートする
import { atom, useRecoilState } from "recoil";
-
atom関数
を使用してuseRecoilState
に必要なパーツ(引数)を作成
const countState = atom<number>({
//ユニークキー
key: "simple/counter",
//初期値
default: 0
});
-
useRecoilState
にstateを引数として入れる
// 変数と関数を同時生成
const [count, setCount] = useRecoilState<number>(countState)
// 関数のみ生成
const setCount = useSetRecoilState<number>(countState)
// 変数のみ生成
const count = useRecoilValue<number>(countState)
-
setCount
でstateを更新する
<button onClick={() => setCount((c) => c + 1)}>Clicked : {count}</button>
全体像
import React from 'react'
import { atom, useRecoilState } from 'recoil'
//stateに必要なパーツ(引数)atom関数を使用
const countState = atom<number>({
//ユニークキー
key: 'simple/counter',
//初期値
default: 0,
})
export const Footer: React.FC = () => {
// useRecoilStateにぶち込む
const [count, setCount] = useRecoilState<number>(countState)
return (
<>
<p>Footer</p>
<button onClick={() => setCount((c) => c + 1)}>Clicked : {count}</button>
</>
}
Selector関数
- atomのstateを加工することが可能
- 複数のatomのセットが可能(やり方不明)
const reCountState = selector<number>({
//ユニークキー
key: 'simple/reCounter',
//atomで作ったstateを3倍に加工する(getはあくまで値を読み取る用)
get: ({ get }) => get(countState) * 3,
//setは値の加工で任意で追加
set: ({ get, set }, newValue) => {
if (typeof newValue == 'number') {
set(countState, newValue * 3)
}
},
})
- selector関数で作ったstateで変数と関数を生成
//selectorで変数と関数を生成
const [reCount, setCount] = useRecoilState<number>(reCountState)
selector、atom、set関数の処理の順序
① atom
で指定してある初期値を取得して表示
② selector
を介して生成されたstate
の値は、atom
の値を参照した後getメソッド
の処理が走った上で表示される
③ set関数で値をセットする
④ selector
で設定されているsetメソッド
の処理が走り、state
が更新される
⑤ ①に戻る
//state生成に必要なatom関数を使用
const countState = atom<number>({
//ユニークキー
key: 'simple/counter',
//初期値
default: 0,
})
//atomの値を加工するselector関数
const reCountState = selector<number>({
//ユニークキー
key: 'simple/reCounter',
//② atom関数で生成したstateの変数を3倍に加工する(※1回目の処理後 3 *2回目の処理後 12)
get: ({ get }) => get(countState) * 3,
//setの方もgetの順番と同じっぽい
set: ({ get, set }, newValue) => {
if (typeof newValue == 'number') {
set(countState, newValue * 3)
}
},
})
export const Footer: React.FC = () => {
//atom関数で生成したstateから変数のみ生成
const [count] = useRecoilState<number>(countState)
//selector関数で生成したstateで変数と関数を生成
const [reCount, setCount] = useRecoilState<number>(reCountState)
return (
<>
{/*① set関数で +1 される(※1回目の処理後 1 *2回目の処理後 4)
③ selectorで加工された値がset関数の引数に入る(※1回目の挿入値(初動は加工されない) 0 ※2回目の挿入値 3)*/}
<button onClick={() => setCount((c) => c + 1)}>atom counter</button>
<p>atom:{count}</p>
<p>selector:{reCount}</p>
</>
)
}
動的にAtomを生成する
- atomFamily関数というもので識別子をつけられる
//atomFamily関数でstateを作成(作成したstateは関数として使う)
const itemStateFamily = atomFamily<number, SerializableParam>({
key: 'atomfamily',
default: 0,
})
//生成した関数に識別子を渡す
const atom = itemStateFamily("My name")
//上記の変数を使って関数・変数を作成
const [state, setState] = useRecoilState(atom)
- atomと違う要素としてdefaultに関数を指定できる
const numStateFamily = atomFamily<number, number>({
key: 'atomfamily',
//識別子として渡したものがここに入る??
default: (i) => i * 5,
})
//defaultに設定した関数の引数に今回の引数が入る
const numAtom = numStateFamily(numName)
動的にSelectorを生成する
export const selectorFamilySample = selectorFamily<number, string>({
key: 'selector-family',
get:
(arg) =>
({ get }) => {
return get(itemStateFamily(arg))
},
set:
(arg) =>
({ set }, value) => {
console.log('value')
console.log(value)
if (typeof value == 'number') set(itemStateFamily(arg), value * 3)
},
})
他コンポーネントからの呼び出し
-
useRecoilState
に必要な引数であるatom関数やselector関数で作ったstate
をexportして外部で使う - 関連してる
state
は更新されると全て再レンダリングが走る
import { countState } from '../RecoilStart/RecoilStart'
export const StateCall: React.FC = () => {
const [callState, setCallState] = useRecoilState<number>(countState)
return (
<>
<button onClick={() => setCallState((c) => c + 1)}>
別コンポーネントで呼び出し
</button>
<p>call:{callState}</p>
</>
)
}