2021/09/20
はじめに
React で Firebase SDK を使っていて,ブラウザに以下の warning が出てきた.
warning 状態
warning_log
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
この警告は,見る限りメモリリークが発生している.タイミングとしては,component の unmount 時である.発生箇所はuseEffect()
となっている.
今回は心当たりが合ったので簡単に問題を修正できた.
まずは修正の前後
元コード
base
const App = () => {
...
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setLoggedIn(true);
setImage(googlesignin_disabled);
} else {
setLoggedIn(false);
}
});
}, []);
return (
...
)
}
修正後コード
fixed
const App = () => {
...
useEffect(() => {
- onAuthStateChanged(auth, (user) => {
+ const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setLoggedIn(true);
setImage(googlesignin_disabled);
} else {
setLoggedIn(false);
}
});
+ return unsubscribe;
}, []);
return (
...
)
}
原因
useEffect()
により component の mount 時に onAuthStateChanged()
で,Auth 状態の変更を subscribe していた.
元コードでは subscribe の解除が行われていない.そこで,onAuthStateChanged()
の戻り値であるUnsubscribe
型を保持しておき,unmount 時に呼び出す.
おわりに
「何故この書き方をすると・・・?」などの疑問については,おそらく React 公式の Hooks の説明ページの中のuseEffect
の説明を見てもらえばよいでしょう.日本語では「副作用フック」のような和訳がなされていた気がする.