こんにちは、株式会社グロービスのフロントエンドエンジニアです
イベントリスナー関連のcleanupコードの重要さについて少し書きたいと思います!
問題の説明
最近、開発しているサービスで、外部APIの導入で下記の現象が起きてました:
ページを変わるたびに、同じリクエストがどんどん増えてきました
- Topページを視聴すると: 1つリクエスト
- 違うページに行くと:2つ同じリクエスト(合計3つ)
- Topページを視聴すると:3つ同じリクエスト(合計6つ)
つまり、3つリクエストの代わりに、急に6つになりました!
🚨 各リクエスト = 💸💸💸 🚨
問題を起こしたコード
Quiz: 下記のコードでは、どういう問題がありますでしょうか?
useEffect(() => {
const fetchWelcomeMessageFromPaidAPI = () => { /*... logic ...*/ }
document.addEventListener('api-initialized', fetchWelcomeMessageFromPaidAPI);
}, [/*... dependencies ...*/]);
React.useEffectの復習
Quizの答え知るなら、次の段落に進んで大丈夫です。
そうじゃなければ、少し復習しましょう。
React.useEffect
を使ったことがありますか?
useEffect(() => {
// some logic
return () => {
// cleanup
};
}, [/* dependencies */]);
上記のhookを知らない方へ、Reactのドキュメンテーションがおすすめです。
useEffect
の中のreturn
の意味を復習しましょう:
-
return
の役割:cleanup コード (例えば、追加されたイベントリスナーの削除など ) -
return
の実行タイミング:- コンポーネントはunmountされる時
- useEffectが実行される時
問題解決
useEffect(() => {
const fetchWelcomeMessageFromPaidAPI = () => {
//... some logic ...
};
document.addEventListener('api-initialized', fetchWelcomeMessageFromPaidAPI);
return () => {
document.removeEventListener('api-initialized', fetchWelcomeMessageFromPaidAPI);
};
}, [/* dependencies */]);
cleanup 関数を追加することで、問題が解決されました。
幸いなことで、早い段階で気づかれて、今回特に損がなかったが、このような片付けはどれだけ大事かということを伝わっている例だなと思いました。
どうやってこのようなleakを防ぐか?
- イベントリスナーを使うなら、必ずブラウザーのdev toolsコンソールで同じイベントリスナーの数が増えていないか確認しましょう (
getEventListeners(domElement)
) - cleanupのreturn関数を忘れないこと 🤗
- 自分でイベントリスナーを追加しなくても、他のエンジニアのPRをちゃんと確認すること
このように確認がちゃんとできたら、今回の問題はなかったでしょう!😅