4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReactAdvent Calendar 2023

Day 5

【React】state変数がオブジェクトのときにやらかしがちなこと

Posted at

はじめに

Reactの公式チュートリアルをやっていてハマったところを解説します。

問題

state変数にオブジェクトが入っているとします。

const [position, setPosition] = useState({ x: 0, y: 0 });

positionを更新したいとき、次のように書いてはいけません。

position.x = 1;
position.y = 2;

以下もダメです。

position.x = 1;
position.y = 2;
setPosition(position);

理由を順番に説明していきます。

state変数の変更はset関数を使いましょう

まず1つ目のコードがダメな理由を説明します。

position.x = 1;
position.y = 2;

前提として、state変数が数字だろうと文字列だろうオブジェクトだろうと、set関数以外で変更してはいけません

ただ、数字や文字列の場合はプリミティブな値なので、それ自体を変化させることは、やろうとしてもできません。

え? こうすれば数字でも変えられるじゃん? と最初は思いましたが、、

const [x, setX] = useState(0);
setX(5);

このコードはxというstate変数の値を0から5に変更しているだけで、0という値自体を5に変えているわけではないです。なので問題ありません。

しかしながら、state変数の値がオブジェクトの場合は、オブジェクト自体の値を書き換えることができてしまいます1

例えば、以下ではpositionというstate変数自体を変化させています。

const [position, setPosition] = useState({ x: 0, y: 0 });
position.x = 1;
position.y = 2;

これの何が問題かというと、Reactがこの変更を検知できないことです。

内部的にはpositionの値は確かに変更されていますが、Reactがそれを検知できないため再レンダリングされず、画面上なんの変更もされていないように見えてしまいます。

解決策

set関数を使用すればReactに変更を検知してもらえます。

新しいオブジェクト{ x: 1, y: 2 }を作成し、setPositionに渡せば、無事に再レンダリングされます。

setPosition({ x: 1, y: 2 });

疑問

ここで疑問に思いました。

わざわざ新しいオブジェクトなんて作らなくても、set関数にpositionを渡せばいいじゃないかと。

冒頭に書いた2つ目のコードです。

position.x = 1;
position.y = 2;
setPosition(position);

しかしながら、これでも画面上positionの値は更新されません。

set関数は、state変数の値が変化したときだけ実行されるからです。

今回の場合、オブジェクトであるpositionxプロパティの値が変わっただけなので、position自体の変更とはみなされず、setPositionは実行されません。

解決策

なので、やっぱり新しいオブジェクトを作って、set関数に渡す必要があります。

setPosition({ x: 1, y: 2 });

終わりに

2つ目のコードがなぜ上手くいかないのかがわからなくて調べて、結果的に理解が深まったので良かったです。

参考

  1. 今回は扱いませんでしたが、配列もオブジェクトと同じくミュータブルなので同じ問題が発生します

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?