本文へスキップ
変数と const

Part 0 · React の前に

1 / 64

変数と const

なぜ React では let をほとんど使わないのか

React のコードを開くと、いちばん最初に目に入るのが const です。ほとんどの行がこれで始まっていると言ってもいいくらいです。

const は「変わらない値」だと説明されることが多いのですが、 それだけだとあとで必ずつまずきます。 const で作ったはずのデータが、いつのまにか書き換わっているからです。

この章では、const が実際には何を守っているのかをはっきりさせます。

変数は、値につけた名前

プログラムでは、あとで使いたい値に名前をつけておきます。これが変数です。

const name = "さとう";

console.log(name); // "さとう"

これで「name と書いたら "さとう" のこと」という約束ができました。 名前をつけておくと、同じ値を何度も書かずに済みますし、 その値が何を表しているのかが読む人に伝わります。

const-object.ts

// const で作ったオブジェクト
export const user = { name: "さとう", age: 20 };

// user そのものを入れ替えることはできない。これを書くとエラーになる
// user = { name: "すずき", age: 30 };

// でも、中身を書き換えることはできてしまう
user.name = "すずき";
user.age = 30;

const と let

変数を作る方法は、いまは 2 つだけ覚えれば十分です。

const name = "さとう";
name = "すずき"; // エラー。あとから入れ直せない

let count = 0;
count = 1; // これは通る
  • const … あとから別の値を入れ直せない
  • let … 入れ直せる

var という古い書き方もありますが、 いま新しく書くコードでは使いません。見かけたら「古いコードだ」と思って大丈夫です。

React ではほとんど const

React のコードを見ると、変数がほぼ全部 const です。 これは行儀の問題ではなく、React の考え方がそうなっているからです。

React では、値を書き換えて画面を変える、ということをしません。新しい値を作って React に渡すと、React が画面を描き直します。 書き換えないので、入れ直せる必要がないのです。

const-object.ts

// const で作ったオブジェクト
export const user = { name: "さとう", age: 20 };

// user そのものを入れ替えることはできない。これを書くとエラーになる
// user = { name: "すずき", age: 30 };

// でも、中身を書き換えることはできてしまう
user.name = "すずき";
user.age = 30;

const が守るのは「名札」だけ

ここが、この章でいちばん大事なところです。

const は「値を変えられなくするもの」ではありません。「その名前に、別の値を入れ直せなくするもの」です。 名前と値の結びつきを固定しているだけで、値そのものには手を出していません。

const user名札{ name: "さとう" }名札を別の箱に付け替えるuser = { name: "すずき" }箱の中の値を書き換えるuser.name = "すずき"
const が固定するのは名札の付け先だけ。箱の中身には関与しない

文字列や数値のような単純な値なら、この違いは表に出てきません。 「入れ直せない」=「変えられない」と考えても、結果は同じだからです。

問題はオブジェクトと配列です。これらは中身を持っています。 そして中身の書き換えは、名札の付け替えではありません。

const のオブジェクトうまくいかない例

入れ替えていないので、const でも止められない

const で作ったのに、中身が書き換わっています

{ name: "すずき", age: 30 }

user = ... なら「名札の付け替え」なのでエラーになりますが、user.name = ... は「箱の中身の書き換え」なので通ってしまいます。

const-object.ts

// const で作ったオブジェクト
export const user = { name: "さとう", age: 20 };

// user そのものを入れ替えることはできない。これを書くとエラーになる
// user = { name: "すずき", age: 30 };

// でも、中身を書き換えることはできてしまう
user.name = "すずき";
user.age = 30;

配列も同じ

配列も中身を持っているので、同じことが起きます。push は「配列を入れ替える」操作ではなく 「配列の中に足す」操作なので、const でも通ります。

const の配列うまくいかない例

要素が 3 つに増えている

push したぶんだけ要素が増えている

["さとう", "すずき", "たかはし"]

const-array.ts

// 配列も同じ。const で作っても中身は増やせる
export const members = ["さとう", "すずき"];

// push は「配列を入れ替える」のではなく「配列の中に足す」操作
members.push("たかはし");

ではどうするか:書き換えずに、新しく作る

中身を書き換えられてしまうなら、書き換えないようにします。 変えたいときは、新しいオブジェクトを作って、そちらを使うという考え方です。

新しく作ったほう直した例

元のデータは無傷のまま

元のほうは、書き換えられていません

元: { name: "さとう", age: 20 }
新しく作ったほう: { name: "すずき", age: 20 }

元の user は最後まで書き換えていません。 変えたいところだけ新しい値にして、 残りは元から写した別のオブジェクトを作りました。

いまは「そういう書き方もある」で十分です。 この写す作業をもっと短く書く方法は分割代入とスプレッド構文の章で、 なぜ React でこの書き方が必要なのかは Part 4 で扱います。

new-object.ts

// 元のデータ。こちらは最後まで書き換えない
export const user = { name: "さとう", age: 20 };

// 書き換える代わりに、新しいオブジェクトを作る。
// 変えたいところだけ新しい値にして、残りは元から写す
export const updated = { name: "すずき", age: user.age };

// user は無傷のまま。updated だけが新しい

理解できたか確かめる

確認クイズ

const で作った変数について、正しいのはどれ?

確認クイズ

次のうち、エラーになるのはどれ?

const-object.ts

// const で作ったオブジェクト
export const user = { name: "さとう", age: 20 };

// user そのものを入れ替えることはできない。これを書くとエラーになる
// user = { name: "すずき", age: 30 };

// でも、中身を書き換えることはできてしまう
user.name = "すずき";
user.age = 30;

この章のまとめ

  • 変数は、値につけた名前
  • const名前と値の結びつきを固定する
  • 固定されるのは名札だけで、オブジェクトや配列の中身は書き換えられてしまう
  • React では基本的に const を使い、let はほとんど出てこない

const-object.ts

// const で作ったオブジェクト
export const user = { name: "さとう", age: 20 };

// user そのものを入れ替えることはできない。これを書くとエラーになる
// user = { name: "すずき", age: 30 };

// でも、中身を書き換えることはできてしまう
user.name = "すずき";
user.age = 30;