2
0

useState での配列変化の検知

React ではuseStateを用いて、コンポーネントにstate変数を紐づけることによって状態を管理できます。

このstate変数には配列を指定することもできます。
ただし、useStateの第2引数として返されるset 関数は、配列に変更が入ったことをObject.is()によって検知しているため、すでにある配列に対して操作を行っても変更が検知されず、状態の変更が反映されないことがあります。

Object.is()は厳密等価演算子===とほとんど同じ判定をしますが、0-0を一致と判定しない点と、NaN同士を一致判定する点で異なっています。


変数に配列を代入するとき、変数には配列自体ではなく配列への参照(格納されているメモリのアドレスのこと)が代入されます。

配列に変更を加えるメソッドの中には、(参照を変えることなく)配列を直接変更するメソッドがいくつかあり、それらを使用してもReact 側へは配列に加えた変更が伝わらないこととなります。

Object.is()と配列

変数に配列を代入するとき、変数には配列自体ではなく配列への参照が代入されます。
そのため、以下のように同じ要素を持つ配列を別々に宣言しても、Object.is()には一致していると判定されません。

const arr = [1, 2, 3, 4]

const arr2 = [1, 2, 3, 4]

console.log(Object.is(arr, arr2))
// false

しかし、別の変数に配列を代入してからその配列に要素を直接追加して、元の変数と比較したときには一致判定がされます。

const initialState = ['a', 'b', 'c']
const state = initialState

state[3] = 'd'

console.log(state)
// [ 'a', 'b', 'c', 'd' ]

console.log(Object.is(state, initialState))
//true

配列に要素を直接追加しても、Object.is()には元と同じ配列であるとみなされて変更が検知できないわけですね。

stateに配列を格納して値を変更するときには、その変更が検知されるような書き方をする必要があります。

新たな配列を返すメソッド

配列を操作するメソッドのうち、変更結果を新しい配列として返すメソッドがいくつか存在します。
基本的にはそれらのメソッドを使用するようにすることで、配列への変更が検知されない事態を避けることができます。

配列操作後に新たな配列を返すメソッドとしては、concat()map()filter()sliceなどが挙げられます。

配列への追加や削除、更新などの用途に応じて以下でみていきます。

配列への追加

スプレット構文やconcatpushunshiftなど

配列への更新

mapspliceなど

配列要素の削除

filterslicespliceなど

配列要素の並び替え

sortreverseなど

直接変更を加えるメソッドを使うには

変更を加えたい配列をあらかじめ複製しておき、複製した配列に対して操作を加えるようにすれば、直接変更を加えるメソッドでも問題なく使用できるので安心です。

2
0
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
2
0