スプレッド構文とは
配列やオブジェクトの要素やプロパティを「展開」して、別の配列やオブジェクトにコピー・結合・分解するための構文です。
具体的な使い方
配列のコピー
const arr1 = [1, 2, 3];
const arr2 = [...arr1];
console.log(arr2); // [1, 2, 3]
// arr1とは別の新しい配列が作られる
配列の結合
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4]
配列の要素の分解
const numbers = [10, 20, 30];
console.log(...numbers); // 10 20 30
// 関数呼び出し時に使うと、配列を個別の引数として渡せます。
function sum(a, b, c) {
return a + b + c;
}
const nums = [1, 2, 3];
console.log(sum(...nums)); // 6
オブジェクトのコピー
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1 };
console.log(obj2); // { a: 1, b: 2 }
オブジェクトのマージ
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 3, c: 4 }
オブジェクトのコピー・更新
const obj = { a: 1, b: 2 };
const copy = { ...obj };
// コピーと更新を同時にできる
const updated = { ...obj, b: 99, c: 3 };
console.log(copy); // { a: 1, b: 2 }
console.log(updated); // { a: 1, b: 99, c: 3 }
Reactでスプレッド構文を使う理由
React(特に useState や useReducer)などの状態管理では、**「イミュータブル(不変)なデータ管理」が基本です。これは、「既存のオブジェクトを直接変更せずに、新しいオブジェクトとして更新する」という考え方です。
スプレッド構文を使わないと・・・
Reactでは、stateやpropsが「変更されたかどうか」を参照の違いで判断します、簡単に言うと、「前回の状態と違うか(===で比較して)」を見て再レンダリングの要否を判断します。しかし、直接変更すると、参照元が同じ、===で同じと見なされてしまうことがあります。
const [user, setUser] = useState({ name: 'Tanaka', age: 25 });
// ageだけ変えたい
const updateAge = () => {
user.age = 30; // ← 直接書き換え
setUser(user); // ← 中身は変わってるけど、オブジェクトとしては同じ
};
- user.age は変わったように見えるが、user 自体の参照(メモリ上の位置)は変わっていない。
- React は user === user なので、「変わっていない」と判断し、再レンダリングされないことがある。
スプレッド構文を使うと・・・
スプレッド構文を使うことで、元の値を変更せずに新しい配列やオブジェクトを作成することができます。
const updateAge = () => {
setUser({ ...user, age: 30 }); // ← 新しいオブジェクトを作る
};
- ...user で元の情報をコピーし、age を上書き。
- 新しいオブジェクトなので、user !== 新しいuser となり、
- React は「変化があった」と認識し、正しく再レンダリングされる