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

Categories:React

起こったこと

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>
    </>
  );
}

参考

返信がありません

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です