スプレッドの復習

中身をばらまく 3 つの点

スプレッド構文は、配列やオブジェクトの中身を 1 つずつ取り出して、別の場所に並べ直す書き方です。書き方は点を 3 つ並べるだけです。

const titles = ["レシピ検索アプリ", "買い物メモツール"]; const nextTitles = [...titles, "写真ギャラリー"]; nextTitles; // ["レシピ検索アプリ", "買い物メモツール", "写真ギャラリー"] titles; // ["レシピ検索アプリ", "買い物メモツール"] もとの配列はそのまま

大事なのは最後の行です。titles は 2 件のまま変わっていません。[...titles, "写真ギャラリー"] は「もとの配列を書き換える」のではなく「もとの中身を並べた新しい配列を作る」からです。

先頭に足したいなら順番を入れ替えるだけです。

const nextTitles = ["写真ギャラリー", ...titles];

オブジェクトでも同じことができる

オブジェクトでもスプレッドが使えます。同じプロパティ名が 2 回出てきたときは、あとに書いたほうが勝ちます。

const work = { id: 1, title: "レシピ検索アプリ", published: false }; const publishedWork = { ...work, published: true }; publishedWork; // { id: 1, title: "レシピ検索アプリ", published: true } work; // { id: 1, title: "レシピ検索アプリ", published: false }

「1 か所だけ変えた新しいオブジェクトを作る」ときの定番の形です。{ ...work, published: true } は、まず work の中身を全部並べ、そのあとに published を上書きしています。

なぜ React でこれが要るのか

React の state は、書き換えるのではなく作り直すものだからです。

第4章で出てくる useState は、値が別のものに入れ替わったときにだけ画面を描き直します。ところが push や代入で中身を直接いじると、配列やオブジェクトそのものは同じ入れ物のままです。React から見ると「何も変わっていない」ので、画面が更新されません。

// 画面が変わらない書き方 works.push(newWork); setWorks(works); // 新しい配列を渡すので画面が変わる setWorks([...works, newWork]);

オブジェクトの state も同じです。

setProfile({ ...profile, title: "フロントエンド担当" });

この「もとを触らずに、新しいものを作って渡す」やり方を不変更新と呼びます。React を書いているあいだ、state を更新するときはほぼ毎回この形になります。第4章の作品の追加と削除で、そのまま回収します。

つまずきどころ

スプレッドがコピーするのは一番外側だけです。中に入れ子のオブジェクトがあると、そこは同じものを共有したままになります。

const profile = { name: "あおい", links: { github: "aoi" } }; const copy = { ...profile }; copy.links.github = "aoi-dev"; profile.links.github; // aoi-dev もとも変わってしまった

入れ子を変えたいときは、内側にもスプレッドを書きます。今はこの落とし穴があることだけ覚えておけば十分です。

演習

作品リストに 1 件足す関数を書きます。もとの配列を書き換えず、新しい配列を返すのがポイントです。

要件

  1. [...works, ...] の形で、もとの配列を書き換えずに新しい配列を返す
  2. 追加する作品は { ...newWork, ... } の形で作り、id と published を足す
  3. id は追加後の件数と同じ番号にする。3 件のリストに足すなら 4 になる
  4. published は false にする

入出力例

addWork([], {"category":"web","title":"レシピ検索アプリ"})[{"category":"web","id":1,"published":false,"title":"レシピ検索アプリ"}] addWork([{"category":"web","id":1,"published":true,"title":"レシピ検索アプリ"}], {"category":"tool","title":"買い物メモツール"})[{"category":"web","id":1,"published":true,"title":"レシピ検索アプリ"},{"category":"tool","id":2,"published":false,"title":"買い物メモツール"}] addWork([{"category":"web","id":1,"published":true,"title":"レシピ検索アプリ"},{"category":"tool","id":2,"published":true,"title":"買い物メモツール"},{"category":"web","id":3,"published":false,"title":"写真ギャラリー"}], {"category":"tool","title":"読書メモアプリ"})[{"category":"web","id":1,"published":true,"title":"レシピ検索アプリ"},{"category":"tool","id":2,"published":true,"title":"買い物メモツール"},{"category":"web","id":3,"published":false,"title":"写真ギャラリー"},{"category":"tool","id":4,"published":false,"title":"読書メモアプリ"}] addWork([], {"category":"tool","title":"買い物メモツール"})[{"category":"tool","id":1,"published":false,"title":"買い物メモツール"}]

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.js
main.js
学習モード

メモ

スプレッドの復習

⌘S で保存