setStateでオブジェクトのプロパティを更新することは可能でしょうか?
以下のようなものです。
this.state = {
jasper: { name: 'jasper', age: 28 },
}
試してみました。
this.setState({jasper.name: 'someOtherName'});
とこれ。
this.setState({jasper: {name: 'someothername'}})
最初のものは構文エラーになり、2番目のものは何もしません。何かアイデアはありませんか?
これには複数の方法があります。stateの更新はasync operationなので、stateオブジェクトを更新するには、setState
を使ったupdater functionを使う必要があります。
*1- 最もシンプルな方法:***。
まず、jasper
のコピーを作成し、そのコピーに変更を加えます。
this.setState(prevState => {
let jasper = Object.assign({}, prevState.jasper); // creating copy of state variable jasper
jasper.name = 'someothername'; // update the name property, assign a new value
return { jasper }; // return new object jasper object
})
Object.assign`を使う代わりに、次のように書くこともできます。
let jasper = { ...prevState.jasper };
2- [spread operator]3を使用します。
this.setState(prevState => ({
jasper: { // object that we want to update
...prevState.jasper, // keep all other key-value pairs
name: 'something' // update the value of specific key
}
}))
注意: Object.assign
と Spread Operator
は、浅いコピー しか作成しませんので、ネストしたオブジェクトやオブジェクトの配列を定義している場合は、別のアプローチが必要です。
stateを次のように定義しているとします。
this.state = {
food: {
sandwich: {
capsicum: true,
crackers: true,
mayonnaise: true
},
pizza: {
jalapeno: true,
extraCheese: false
}
}
}
pizza オブジェクトの extraCheese を更新する。
this.setState(prevState => ({
food: {
...prevState.food, // copy all other key-value pairs of food object
pizza: { // specific object of food object
...prevState.food.pizza, // copy all pizza key-value pairs
extraCheese: true // update value of specific key
}
}
}))
Todoアプリがあって、このフォームでデータを管理しているとします。
this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}
任意のTodoオブジェクトのステータスを更新するには、配列に対してマップを実行し、各オブジェクトの一意の値をチェックします。condition=true
の場合、更新された値を持つ新しいオブジェクトを返し、そうでなければ同じオブジェクトを返します。
let key = 2;
this.setState(prevState => ({
todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)
}))
提案: オブジェクトがユニークな値を持たない場合は、配列のインデックスを使用します。
最初のケースは確かにシンタックスエラーです。
あなたのコンポーネントの残りの部分を見ることができないので、なぜここでステートにオブジェクトを入れ子にしているのかわかりません。コンポーネントの状態にオブジェクトを入れ子にするのはよくありません。初期状態をこう設定してみてください。
this.state = {
name: 'jasper',
age: 28
}
そうすれば、名前を更新したいときには、単に
this.setState({
name: 'Sean'
});
これで狙い通りになるのでしょうか?
より大きくて複雑なデータストアには、Reduxのようなものを使います。しかし、それはもっと高度なものです。
コンポーネントの状態に関する一般的なルールは、コンポーネントのUI状態(アクティブ、タイマーなど)を管理するためにのみ使用することです。
これらのリファレンスをチェックしてみてください。
もう一つの方法は、Jasperオブジェクトから変数を定義して、変数を呼び出すことです。
*Spread operator:ES6**。
this.state = { jasper: { name: 'jasper', age: 28 } }
let foo = "something that needs to be saved into state"
this.setState(prevState => ({
jasper: {
...jasper.entity,
foo
}
})