自己学習メモ
Recoilは状態管理として簡単に使えるが、たまにつまりポイントがあるのでそのあたりのメモ
※Recoilがどこでもよしなに更新してくれるだろうくらいで思っているとつまる
環境
- react": "^18.2.0"
- recoil": "^0.7.5"
例
コンポーネント描画時にイベント登録を行いRecoilが後で更新されたケース
以下では、resizeイベントを登録してボタンでRecoilを更新する
Valueが更新されないコード
useEffectで一度だけイベント登録して、listenerで参照する場合
atomが更新されてもlistenerのなかでは古い情報が参照される
import { useEffect } from "react";
import { atom, useRecoilState } from "recoil";
const isLoginAtom = atom({
key: "isLogin",
default: false,
});
const Test: React.FC = () => {
const [isLogin, setIsLogin] = useRecoilState(isLoginAtom);
const resizeEvent = (_e: Event) => {
console.log("isLogin", isLogin);
};
useEffect(() => {
window.addEventListener("resize", resizeEvent);
return () => {
window.removeEventListener("resize", resizeEvent);
};
}, []);
return <button onClick={() => setIsLogin(!isLogin)}>LOGIN</button>;
};
export default Test;
Recoil Valueが更新されるコード
useEffectのdependencyにlistenerを指定
listenerの中で最新のValueが取得される
import { useEffect } from "react";
import { atom, useRecoilState } from "recoil";
const isLoginAtom = atom({
key: "isLogin",
default: false,
});
const Test: React.FC = () => {
const [isLogin, setIsLogin] = useRecoilState(isLoginAtom);
const resizeEvent = (_e: Event) => {
console.log("isLogin", isLogin);
};
useEffect(() => {
window.addEventListener("resize", resizeEvent);
return () => {
window.removeEventListener("resize", resizeEvent);
};
}, [resizeEvent]);
return <button onClick={() => setIsLogin(!isLogin)}>LOGIN</button>;
};
export default Test;
Recoil Valueが更新されるコード2
Recoilのsnapshotから最新Valueを取得
import { useEffect } from "react";
import {
atom,
RecoilState,
RecoilValue,
useRecoilCallback,
useRecoilState,
} from "recoil";
const isLoginAtom = atom({
key: "isLogin",
default: false,
});
const Test: React.FC = () => {
const [isLogin, setIsLogin] = useRecoilState(isLoginAtom);
const getRecoilStateSync = useRecoilCallback(
({ snapshot }) =>
(state: RecoilState<unknown> | RecoilValue<unknown>): unknown => {
return snapshot.getLoadable(state).contents;
},
[]
);
const resizeEvent = (_e: Event) => {
const isLogin = getRecoilStateSync(isLoginAtom);
console.log("isLogin", isLogin);
};
useEffect(() => {
window.addEventListener("resize", resizeEvent);
return () => {
window.removeEventListener("resize", resizeEvent);
};
}, []);
return <button onClick={() => setIsLogin(!isLogin)}>LOGIN</button>;
};
export default Test;