🦅
アンマウント時のステート更新エラーへの対処
はじめまして。
プログラミング勉強中のあかしと言います。
初めて記事を書くので、至らない所が多々あるかと思いますが、
良かったら読んだやってください。
環境
記事の内容とは直接関係無いものもありますが、以下の様な環境です。
package.json
"dependencies": {
"@chakra-ui/icons": "^1.0.4",
"@chakra-ui/react": "^1.3.0",
"@emotion/react": "^11",
"@emotion/styled": "^11",
"firebase": "^8.10.0",
"framer-motion": "^6",
"next": "12.1.6",
"npm": "^8.13.2",
"react": "17.0.2",
"react-confetti": "^6.1.0",
"react-dom": "17.0.2",
"react-hook-form": "^7.33.1",
"react-icons": "^4.4.0",
"react-use": "^17.4.0",
"recoil": "^0.7.4",
"recoil-persist": "^4.2.0"
},
"devDependencies": {
"@types/node": "18.0.0",
"@types/react": "17.0.2",
"@types/react-dom": "17.0.2",
"eslint": "8.18.0",
"eslint-config-next": "12.1.6",
"typescript": "4.7.4"
}
開発中のアプリについて
ヘッダーが認証状態において、以下の2パターンに分かれます。
-
ログイン時:ユーザーのアバター、ログアウトのアイコン
-
ログアウト時:新規登録のアイコン、サインインのアイコン
エラー内容
ページを遷移する際に、以下のエラーが出ました。
要は「アンマウントされたのに、ステートの更新はできないよ」と言っています。
どうやら原因はログイン時にユーザーのアバター画像をステートで更新していたことでした。
エラーへの対処
async/awaitだったり、useEffectだったり色々と試してみたのですが、
アプリの状況に合うのは以下の記事の内容でした。
対処方法は、マウント状態を監視する変数を用意し、変数がtrue(マウントしている)の時のみステートの更新を行う様にします。
様々なコンポーネントで再利用したかったので、カスタムフックを用意しました。
useIsMounted.ts
import { useEffect, useRef } from "react";
export default function useIsMounted() {
// isMountedにはマウント状態をbooleanで管理
const isMounted = useRef(false);
useEffect(() => {
// マウント時はtrue
isMounted.current = true;
return () => {
// アンマウント時はfalse
isMounted.current = false;
};
});
return isMounted;
}
そして、アンマウント時にステートを更新していた部分に、
isMountedを用いてマウントしている時のみステートを更新する様に変更しました。
useIsMounted.ts
// 用意したカスタムフックをインポート
import useIsMounted from "../hooks/useIsMounted";
const [avatarUrl, setAvatarUrl] = useState<any>("");
// マウント状態を
const isMountedRef = useIsMounted();
const docRef = db.collection("users").doc(uid);
docRef
.get()
.then((doc) => {
if (doc.exists) {
// マウント時のみステートを更新
if (isMountedRef.current) setAvatarUrl(doc.data()?.imageUrl);
} else {
alert("No such document!");
}
})
.catch((error) => {
alert(error);
});
これで、エラーが出なくなりました。
最後に
拙い知識で書いた記事を最後まで読んでいただき、ありがとうございました。
間違い等ありましたら、教えていただけると大変ありがたいです。
Discussion