Reactのmapメソッドに潜むパフォーマンスの罠
5分25秒 | WEBREACT
基本情報技術者試験の頻出テーマを解説した音声コンテンツです。
トランスクリプト(字幕テキスト)
The Debateへようこそ。今回は React での リストレンダリング についてです。データから動的に UI要素 のリストを作り出す、おなじみの処理ですよね。 そこで今日の論点なんですが、 JavaScript の .map() メソッドは本当に React のリスト表示における 最適解 と言えるんでしょうか? それとも、その手軽さがかえってより深刻な問題を隠してしまっているのか、そのあたりを議論したいですね。 私はですね、 .map() こそが React の思想を体現した 直感的でかつパワフルな基本ツール だと考えています。 なるほど。私は逆で、そのシンプルさが大規模なデータとか、複雑な構造を扱う際の 落とし穴 になりがちじゃないかなという立場です。 ではまず私の立場からお話しますね。昔、静的な HTML でリストを作っていた頃を思い出してほしいんですけど、それこそ1、2、3と LIタグ を手で数えるように書いていたじゃないですか。 ああ、ありましたね。それが .map() は データ配列 を渡すだけで、マップという感じで一瞬で コンポーネント のリストに変換してくれます。 これこそがまさに UIはデータの状態を反映する という React の核となる考え方そのものだと思うんですよね。 はい。その魔法のような手軽さはもちろん認めます。ですが、その手軽さこそが、まあ、 諸刃の剣 だと。 小規模なリストなら問題ないんですけど、アイテム数が数百、数千と増えた時、 .map() はリストの全アイテムに対応する DOM要素 を愚直に全部生成してしまう。これで パフォーマンスが著しく低下する わけです。 ほう。なので、初期段階から React.memo とか、あるいは 仮想スクロール といった より高度な最適化 を視野に入れるべきじゃないでしょうか? なるほど。ただ、そのパフォーマンスの問題でよく指摘される keyプロップ については少し見方が違いますね。あれは .map() 自体の欠陥というより、 React の 基本的なルール ですよね。 データベースのIDみたいな安定した一意の値を使いば React の 差分検出 は非常に効率的に機能するはずです。 確かに理論上はそうですね。でも実務の現場ではどうでしょうか? .map() が手軽なせいで、つい配列の インデックス を key にしてしまうケースが後を絶たない。 ああ、それはよく聞く話ですね。 インデックス を key に使うと React は要素の 個性を認識できなく なってしまうんです。 例えばリストの先頭にアイテムを追加すると、 React は全要素が中身だけ変わったと誤認して、結果的に全 コンポーネント の 再レンダリング と、なんと 再マウント まで引き起こしてしまう。 これは単なるバグというより 根本的なパフォーマンスの無駄遣い なんです。 以前まさにこれが原因で ドラッグアンドドロップ機能 に 致命的なバグ が生まれたプロジェクトがありましたよ。 うわあ、それは手痛い経験ですね。しかし、それって開発者の知識の問題であって、 メソッド 自体の欠陥とは言えないのでは? ほとんどの ユースケース ではリストの数って限られてますし、数千アイテムを扱うような 無限スクロール はまだ 特殊な例 かなと感じますが。 いえ、その見方にはちょっと同意しかねますね。今の Webアプリケーション で 無限スクロール ってもはや 特殊ケースではない と思うんです。その スケーラビリティ の問題は実は データ構造 の複雑さと密接に関係してきます。 例えば API から返される ネストされたJSON を扱う場合を考えてみてください。 ああ、それは コンポーネント 側の責務かなと。データをどう表示するかは コンポーネント の設計次第で、 .map() をネストして使えば 階層構造 も表現できるはずです。 柔軟に対応できますよ 。 しかし、そのために .map() を呼び出す前に再帰的な関数でデータを一度フラットな構造に変換するとか、結構複雑な前処理が必要になることが多いじゃないですか。 そうなった時、もはや .map() は シンプルな解決策 と言えるんでしょうか?単純な一次元配列を前提とした手法であることの、なんていうか、 限界 がそこに見えてくる気がします。 まとめますと、私は、やはり .map() は React における リストレンダリング の 第一選択肢 であり続けると考えています。そのシンプルさと宣言的な性質は 何物にも代えがたいメリット です。 重要なのは keyプロップ の役割といった React の 基本原則 を正しく理解して、適切に使うこと、それに尽きるかなと。 私の考えとしては、 .map() は便利な出発点ではあるんですけど、 万能薬ではない ということですね。 アプリケーションが扱うデータの規模とか構造を最初から考慮して、パフォーマンスが懸念されるなら、ためらわずに 仮想スクロール のような より高度な戦略 を設計に組み込むべきです。その判断を先延ばしにするべきじゃないと思います。 なるほど。一つの基本的な メソッド をとっても、その適用範囲とか潜在的な課題について、これだけ深い議論ができるわけですね。 そうですね。今回触れた 仮想スクロール の実装とか、複雑な データ構造 をどうエレガントに扱うかなど、マテリアルにはさらに 探求すべき点 が残されていると思います。
このコンテンツは Web society で視聴・学習できます。