【React】stateが更新できない・・?症状と対策を紹介

Contents

起こったこと

React hookの一つ、useStateを使ってオブジェクトのstateを更新する際に、以下のように書いてもコンポーネントが再レンダリングされませんでした。

import React, { useState } from "react";export default function App() {  const [person, setPerson] = useState({name: "hoge", age: 29});  const changeAge = () => { person.age = person.age + 1; setPerson(person);  };  return ( <><p>Nage: {person.name}</p><p>Age: {person.age}</p><button onClick={changeAge}>add Age</button> </>  );}

原因と対策

公式ドキュメントを調べると、state更新と再レンダリングに関して以下のような記載が。

現在値と同じ値で更新を行った場合、React は子のレンダーや副作用の実行を回避して処理を終了します(React は Object.is による比較アルゴリズムを使用します)。

要するに、ReactはObject.isによる判定結果がtrueの場合は再レンダリングを実施せず、falseの場合に再レンダリングを実行する、という挙動をするようです。

オブジェクトの場合は、参照値(プロパティ)を更新するだけでは実体(参照元メモリアドレス)が変わらない、つまり「同じ値」が保持されることになるので、再レンダリングが行われなかったということでした。

この対策としては、スプレッド演算子を利用したshallow copy(参照値のみのコピー)を利用して新しいオブジェクトを作成するという方法が取れます。これによってObject.isの結果がfalseになるため、再レンダリングを実行できます。

import React, { useState } from "react";export default function App() {  const [person, setPerson] = useState({name: "hoge", age: 29});  const changeAge = () => { // personをshallow copyしてstate更新 setPerson({...person, age: person.age + 1});  };  return ( <><p>Nage: {person.name}</p><p>Age: {person.age}</p><button onClick={changeAge}>add Age</button> </>  );}

参考

最新情報をチェックしよう!