はじめに
Reactを触っていく中で、objectの中にあるobjectへの値の更新の仕方で詰まったので、
備忘録として残すとともに、何かの参考になれば幸いです。
サンプルコード
例として、以下のコードを使用する。
- 登録ボタンがクリックされたらonClickが実行される。
- person.nameをTaroに変更する。
- person.detail.hobbyをプログラミング、TVゲームという値に変更する。
- 変更された値を画面に表示する。
interface Person = {
name: string;
age: number;
detail: {
birthday: string;
hobby: string[];
};
}
const basePerson: Person = {
name: '',
age: 0,
detail: {
birthday: '',
hobby: [],
},
};
export const Sample: FC = memo(() => {
const [person, setPerson] = useState<Person>(basePerson);
const onClick = () => {
const newHoby = ['プログラミング', 'TVゲーム'];
setPerson((prevState) => ({ ...prevState, name: 'Taro' }));
setPerson((prevState) => ({
...prevState,
detail: { birthday: person.detail.birthday, hobby: newHoby },
}));
};
return (
<Container maxW="100%">
<Button colorScheme="teal" onClick={onClick}>
登録
</Button>
<p>{person.name}</p>
<p>{person.detail.hobby}</p>
</Container>
);
});
解説
通常のobjectの要素を更新する際は、
setPerson((prevState) => ({ ...prevState, name: 'Taro' }));
の様に、現在のstateを関数で渡し、要素を更新する。
しかし、detail要素の様に、objectの中にあるobjectの要素を更新する場合は、
setPerson((prevState) => ({
...prevState,
detail: { birthday: person.detail.birthday, hobby: newHoby },
}));
の様に、現在のstateを展開した後、
detail: { birthday: person.detail.birthday, hobby: newHoby },
と、objectの要素を書き出さなければならない。(もっといい書き方があるかもしれないが...)
また、以下のように、stateを関数で渡さない場合、2回目のsetが行われた時点で、1回目にsetした「Taro」の値が消されてしまうので注意。
setPerson({ ...person, name: 'Taro' }); // 1回目のset
setPerson({ // 2回目のset
...person,
detail: { birthday: person.detail.birthday, hobby: newHoby },
});