⛰️
ReactでuseStateの中身を連想配列で持つ場合の更新
Reactで連想配列をuseStateに入れて管理したときに、状態が更新されなくて困りました。
例えばこのようなデータを...
data = {
name: "東京",
num: 1
}
ひとつのuseStateに入れたら...
const [setting, setSetting] = useState(data)
このようにしても更新されず...💦
const changeName = (e) => {
setSetting((_setting) => {
_setting.name = e.target.value
return _setting
})
}
更新するには、配列を複製、複製の中身を更新して、戻してやる必要があるみたい
const changeName = (e) => {
let _copy = JSON.parse(JSON.stringify(setting)) // 複製
_copy.name = e.target.value // 複製を更新
setSetting(_copy) // 戻す
}
以下のようなアドバイスをいただいたので追記します。
こちらの方が良いですね。記事にしてよかった!
【追記1】オブジェクト生成による状態更新
const changeSetting = (e: React.ChangeEvent<HTMLInputElement>) => {
setSetting((preSetting) => ({
...preSetting,
name: e.target.value
}))
}
【追記2】useImmerによる状態管理
import { useImmer } from "use-immer"
const [data, setData] = useImmer(data_INI);
const changeData = (e: React.ChangeEvent<HTMLInputElement>) => {
setData((draft) => {
draft.name = e.target.value;
})
}
TypeScriptでまとめるとこのように。(CodeSandbox)
Discussion
Reactはstateの更新をObject.isで評価しているので、当初の書き方ではsetSetting後にコンポーネントの再レンダリングが起きなかったのだと思います。
(コピーを作成してsetStateした場合に更新されるのも上記が理由)
のように、別オブジェクトを生成しnameだけ書き換えてあげるとひと手間減るかもしれません👀
ありがとうございます。
いいですね!可読性もありますし。
試してみて、記事に追記させていただきました