結論
普通に使ってる分には起こらなさそう。
検証した環境
| ライブラリ・FW | バージョン |
|---|---|
| react | 18.2 |
| Next.js | 13.14 |
今回のテーマ
- HTTPリクエストの結果が返ってくる前にコンポーネントをアンマウントすると、メモリリークは起こるのか調べてみた。
ちょっと仕事でこの辺りの挙動について知りたくなったので調べてみました!
メモリリークとは
- プログラムによってメモリを確保したものの
解放されないままプログラムが終了してしまい
ヒープ領域をムダにロックしちゃってる状態を指します。
reactで起こるメモリリーク
ではreactではどういうケースでメモリリークが起こるんでしょうか?
こちらの記事によると要因は以下の3つらしいです。
- DOMイベントリスナー
- WebSocket サブスクリプション
- APIへのリクエスト
今回はAPIリクエストのレスポンスが返ってくる前にコンポーネントをアンマウントするとメモリリークが起こるのか検証していきたいと思います。
https://dev.to/jeremiahjacinth13/memory-leaks-how-to-avoid-them-in-a-react-app-1g5e#:~:text=Causes%20of%20Memory%20Leaks%20in,a%20request%20to%20an%20API
検証方法
こちらに2つのページを用意しました。
- 1ページ目のボタンを押してからリンクを押すと、fetch中にTestコンポーネントをアンマウントし(DOMツリーから外し)てTest2コンポーネントを表示します。
そうするとレスポンスを返す先がなくなったPromiseオブジェクトだけが残ってメモリリークが起こるはず、、、!
ということで、その時のメモリの状態をdevtoolsのパフォーマンスタブから記録して眺めていきます。
// 1ページ目
const Test = () => {
const [value, setValue] = useState(0);
// あり得ないほどレスポンスが遅いAPIのダミー
const neverEndingdummyRequest = () => {
return new Promise((resolve, reject) => {
// 10000秒後にstate更新
setTimeout(() => {
resolve(setValue(value + 1));
}, 10000000);
});
};
const handleValue = async () => {
await neverEndingdummyRequest();
};
return (
<>
<p>{value}</p>
<button onClick={handleValue}>request</button>
<Link href="/test2">test2</Link>
</>
);
};
// 2ページ目
const Test2 = () => {
return (
<>
<p>test2</p>
<Link href="/test">testへ</Link>
</>
);
};
何もしない場合
リクエスト・アンマウントしまくる
- 次に40秒間リクエストとページ遷移を繰り返しまくった時のメモリです。
右肩上がりにメモリの使用量が増えてますね。
しかしメモリリークしているなら操作をやめてもグラフは減らないはずです。これではやめた後どうなっているのかわかりません。次はその辺りを検証してみましょう。
リクエスト・アンマウントしまくった後、何もしない
最後に
今回の記事での環境以外にも色々と検証してみたんですが、結局メモリリークを再現できませんでした。
ちなみにreact18.2での検証でしたが、react18以前ではメモリリークを警告するエラーが出てたそうです。
しかしこの警告もAPIについての文脈じゃなさそうなので、考慮しなくて良さそう。
結論としてはあまりメモリリークを意識してreactを書く必要はなさそうってところですかね...
なんか釈然としないですが今回はこんなところで終わろうと思います。
お読みいただきありがとうございました!



