LoginSignup
1
0

More than 1 year has passed since last update.

stateがオブジェクトの時の更新時の注意点とリセット方法について

Posted at

stateがオブジェクトの時の更新時の注意点とリセット方法について

stateがオブジェクトの時の更新時の注意点が少しわかりずらかったのでまとめてみた。

完成画像
スクリーンショット 2023-01-28 12.21.34.png

完成コード
Form.jsx(state更新用関数のchangeName,changeAgeなどにsetObjが①②と2つずつあるがどちらを使用しても良い。)

import { useState } from "react";


const Form = () => {
 const personObj = { name: "John", age: 20, job: "student" };


 const [obj,setObj] = useState(personObj);


 // 名前、年齢、職業を入力するたびに変更する
 const changeName = (e) => {
   setObj(prev => ({ ...prev, name: e.target.value })) /// ①
   setObj(() => ({ name: e.target.value, age: obj.age, job: obj.job }))  /// ②
 }
 const changeAge = (e) => {
   setObj(prev => ({ ...prev, age: e.target.value }))
   setObj(() => ({ name: obj.name, age: e.target.value, job: obj.job  }))
 }
 const changeJob = (e) => {
   setObj(prev => ({ ...prev, job: e.target.value }))
   setObj(() => ({ name: obj.name, age: obj.age, job: e.target.value }))
 }


 // 入力フォームの値のリセット
 const valueReset = () => {
   setObj({ name: "", age: "", job: "" })
 }


 return (
   <>
     <h3>Name:{obj.name}</h3>
     <h3>Age:{obj.age}</h3>
     <h3>Job:{obj.job}</h3>
     <input id="form1" onChange={changeName} value={obj.name} />
     <input id="form2" onChange={changeAge} value={obj.age} type='number' />
     <input id="form3" onChange={changeJob} value={obj.job} />
     <div><button onClick={valueReset}>リセット</button></div>
   </>
 )
};


export default Form;

参考資料
https://amateur-engineer.com/react-usestate-object-update/

オブジェクトの更新方法は、changeName関数の中で記載した①②といった感じで2種類あるらしい。

①「…prev」でオブジェクトにある全てのプロパティの値をstate更新用関数のsetObjに渡し、変更するプロパティの箇所だけ記述する方法(下記の場合、nameプロパティの値を変更するということ)

 setObj(prev => ({ ...prev, name: e.target.value }))

②オブジェクトの各プロパティを呼び出し、変更する箇所だけ更新する方法(下記の場合、nameプロパティの値を変更するということ)

setObj(() => ({ name: e.target.value, age: obj.age, job: obj.job }))

②だと、更新したいオブジェクトのプロパティ以外もage: obj.ageのように記述しないと、入力したとき(setObj関数でstateを更新したとき)に値が設定されていないため、その値が表示されなくなる。

ここからは、jobプロパティの中身を更新したとき、setObj関数の中にageプロパティを指定しなかった時の挙動を確認した。

const changeJob = (e) => {
   setObj(() => ({ name: obj.name, age: obj.age, job: e.target.value }))
 }

↓こちらに変更

const changeJob = (e) => {
   setObj(() => ({ name: obj.name, job: e.target.value }))
 }
・・・jobプロパティを更新するときにageプロパティを指定しなかった。

jobプロパティを更新する入力フォーム(上から3つ目)に「Fighter」という値を入力すると以下のようになる。

入力前
スクリーンショット 2023-01-28 11.51.06.png

入力後
スクリーンショット 2023-01-28 11.51.53.png

setObjのstate更新用関数の中にageプロパティを設定していないため、ageプロパティの値が破棄されてしまった。
このようにならないように、ageプロパティの値を維持しておくためには、②のようにオブジェクトのプロパティを全て書くか、①のようにオブジェクトをスプレッド構文で展開し全てのプロパティを取得するかしなければいけない。

また、リセット時も更新時と同じようにしなければいけないらしい。

リセットボタン押下時に実行される関数にageプロパティの記述を削除してみた。

// 入力フォームの値のリセット
 const valueReset = () => {
   setObj({ name: "", job: "" })
 }

リセットボタン押下前
スクリーンショット 2023-01-28 11.51.06.png

リセットボタン押下後
スクリーンショット 2023-01-28 12.00.36.png

上記のようにvalueReset関数にageプロパティを除いたために、ageプロパティの値が削除されず、値が残り表示されたままとなった。
リセットボタンなどで入力フォームの値を全て削除したいときは、下記のようにオブジェクトのプロパティを全て記述しなければいけない。

// 入力フォームの値のリセット
 const valueReset = () => {
   setObj({ name: "", age: "", job: "" })
 }

まとめ

stateのオブジェクトの値を更新するときは、以下のようにするのが良いのかもしれない。

setObj(prev => ({ ...prev, name: e.target.value }))

…prevでスプレッド構文を使用し、オブジェクトの中身を全て取得し、更新するプロパティだけ更新する。

1
0
3

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