初めに
React でリストをレンダリングするときに、map
を使って key
を指定することは必須です。
key
の指定方法として インデックスを使う方法 をよくUdemy講座や初心者向けの解説記事などで散見します。
私も最初はindexを利用したコーディングをしていたのですが、
勉強していく中でそれは思わぬバグを踏む可能性や効率的なレンダリングではないことに気づいたので記事にします。
実際に React の公式ドキュメントでも key
には一意の識別子を使うことを推奨していますが、なぜインデックスを key
に使うのが問題になるのでしょうか?
▼以下参考
この記事では、以下の流れで key
に関する問題を詳しく解説し、適切な方法を紹介していきます。
記事の流れ
1.key
を設定しないと何が問題なのか?
2. key
にインデックスを使うと何が問題なのか?
3. ではどうすればよいのか?
4. まとめ
各コードの実行結果のスクリーンショットや、コンソールでのレンダリング状況も掲載するので、実際にどのような挙動になるのかも分かりやすく解説します。
また、そもそもkeyなんて知らないよという方も読んで雰囲気がわかるようにはなっているので、Reactを触り始めた方にはぜひ読んでほしいです。
それでは、まず key
にインデックスを使うと何が問題になるのかを見ていきましょう!
key
を設定しないと何が問題なのか?
React では、リストをレンダリングするときに key
を指定しないと、要素の差分を適切に管理できず、不要な再レンダリングが発生することがあります。
以下のコードを見てみましょう。
import { useState } from 'react';
import './App.css';
function App() {
const [tasks, setTasks] = useState(["タスク1", "タスク2", "タスク3"]);
const [newTask, setNewTask] = useState("");
const addTask = () => {
if (newTask.trim() === "") return;
setTasks([...tasks, newTask]);
setNewTask("");
};
return (
<>
<h1>タスク管理アプリ</h1>
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
placeholder="新しいタスクを入力"
/>
<button onClick={addTask}>追加</button>
<ul>
{tasks.map((task) => (
<li>{task}</li>
))}
</ul>
</>
);
}
export default App;
このコードでは key
を指定していません。そのため、リストの更新時に React はどの要素が新しく追加されたのかを正しく識別できず、不要な再レンダリングが発生する可能性があります。
実行画面
コンソールの様子
keyにはしっかりとユニークなIDを追加しようね
と怒られていますね
次に、key
にインデックスを使った場合にどのような問題が起こるのかを見ていきましょう。
key
にインデックスを使うと何が問題なのか?
いったんの解決策
や初心者向け説明
でkeyにindexを設定しているコードを散見します。
key
にインデックスを指定することは一見簡単な解決策に思えます。
しかし、実際には以下のような問題が発生します。
コード例
import { useState } from 'react';
import './App.css';
function App() {
const [tasks, setTasks] = useState(["タスク1", "タスク2", "タスク3"]);
const [newTask, setNewTask] = useState("");
const addTask = () => {
if (newTask.trim() === "") return;
setTasks([...tasks, newTask]);
setNewTask("");
};
return (
<>
<h1>タスク管理アプリ</h1>
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
placeholder="新しいタスクを入力"
/>
<button onClick={addTask}>追加</button>
<ul>
{tasks.map((task, index) => (
<li key={index}>{task}</li>
))}
</ul>
</>
);
}
export default App;
key
にインデックスを使うと発生する問題
-
リストの順番が変わると、React が正しく識別できない
- 並び替えが発生すると、React が要素を誤認識し、意図しないレンダリングが起こることがあります。
-
新しい要素が追加・削除されると、不要な再レンダリングが発生する
- 先頭に新しい要素を追加すると、すべてのインデックスが変わるため、React が正しく認識できずに過剰な更新が発生します。
実行画面とコンソールの様子
コンソールの挙動の原因
追加前:
0 → "タスク1"
1 → "タスク2"
2 → "タスク3"
初期で上のようなリストが、追加をすることで以下のようになります。
追加後:
0 → "新しいタスク" (本来のタスク1の `key=0` に変更)
1 → "タスク1" (本来のタスク2の `key=1` に変更)
2 → "タスク2" (本来のタスク3の `key=2` に変更)
3 → "タスク3"
このように、既存のすべての key
がズレてしまい、React が「リストのすべての要素が変わった」と誤認識してしまいます。
reactの強みである仮想DOMによる差分だけのレンダリングが上手に機能していませんね。
ではどうすればよいのか?
key
にインデックスを使うと問題が発生するため、リストの各要素にユニークな識別子(ID)を key
に設定する ことが推奨されます。
適切な key
の設定方法
import { useState } from 'react';
function App() {
const [tasks, setTasks] = useState([
{ id: 1, name: "掃除" },
{ id: 2, name: "洗濯" },
{ id: 3, name: "料理" }
]);
const [newTask, setNewTask] = useState("");
const addTask = () => {
if (newTask.trim() === "") return;
const newTaskObj = { id: Date.now(), name: newTask };
setTasks([newTaskObj, ...tasks]);
setNewTask("");
};
return (
<>
<h1>タスク管理アプリ</h1>
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
placeholder="新しいタスクを入力"
/>
<button onClick={addTask}>追加</button>
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.name}</li>
))}
</ul>
</>
);
}
export default App;
実行画面とコンソールの様子
なぜこのような書き方が良いか?
- 要素が並び替えられても
key
が変わらないため、React が適切に差分を認識できる - 要素を追加・削除しても、既存の要素の
key
が変わらず、不要な再レンダリングを防げる
このように、適切な key
を設定することで、React のレンダリングが最適化され、意図しない挙動を防ぐことができます。
まとめ
key を設定しないと、React が要素の変更を適切に判断できず、不要な再レンダリングが発生する。
key にインデックスを使用すると、リストの並び替えや要素の追加・削除時に key がずれてしまい、意図しないレンダリングが起こる。
最適な key 設定は、ユニークな識別子(ID)を使用すること。
key を適切に設定することで、React の仮想DOMが最大限活かされ、効率的なレンダリングが実現できる。
React でリストを扱う際には、常に key の適切な指定を意識し、最適なパフォーマンスを確保しましょう!
まとめ
-
key
を設定しないと、React が要素の変更を適切に判断できず、不要な再レンダリングが発生する。 -
key
にインデックスを使用すると、リストの並び替えや要素の追加・削除時にkey
がずれてしまい、意図しないレンダリングが起こる。 -
最適な
key
設定は、ユニークな識別子(ID)を使用すること。 -
key
を適切に設定することで、React の仮想DOMが最大限活かされ、効率的なレンダリングが実現できる。
React でリストを扱う際には、常に key
の適切な指定を意識し、最適なパフォーマンスを確保しましょう!
🎉 JISOUのメンバー募集中! 🎉
プログラミングコーチング JISOU では、新たなメンバーを募集しています。
日本一のアウトプットコミュニティで一緒に学び、成長し、キャリアアップを目指しませんか?💻✨
🌟 JISOUで得られること
入ったばかりですが、本当に多くのことを学べます
- 実践的なアウトプットで確実なスキルアップ
- プロのコーチによるマンツーマン指導
- 成長意欲の高い仲間と切磋琢磨できる環境
- キャリアアップに直結する実践的なアドバイス
📢 詳細はこちら
興味のある方は、ぜひ公式ホームページをチェックしてください👇
🔗 JISOU公式ホームページ
一緒に日本一のアウトプットコミュニティを作り上げましょう!🎯