回答:
状態更新があるので、これを行うための複数の方法がありますが、非同期操作ので、状態オブジェクトを更新するために、私たちが使用する必要があり、アップデータ機能をとsetState
。
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- スプレッド演算子の使用:
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
は浅いコピーのみを作成するため、ネストされたオブジェクトまたはオブジェクトの配列を定義している場合は、別のアプローチが必要です。
状態を次のように定義したとします。
this.state = {
food: {
sandwich: {
capsicum: true,
crackers: true,
mayonnaise: true
},
pizza: {
jalapeno: true,
extraCheese: false
}
}
}
ピザオブジェクトの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
)
}))
提案:オブジェクトに一意の値がない場合は、配列インデックスを使用してください。
jasper
オブジェクトから他のプロパティが削除され、console.log(jasper)
キーが1つだけ表示されますname
。年齢は表示されません:)
jasper
あるobject
、最善のかどうか、他のより良いソリューションが可能:)していることがありません
Object.assign
オペレータのディープコピープロパティも拡散もしないことを述べておくとよいでしょう。この方法では、lodashのような回避策使用する必要がありますdeepCopy
など
let { jasper } = this.state
?
これが最も速く、最も読みやすい方法です。
this.setState({...this.state.jasper, name: 'someothername'});
this.state.jasper
すでに名前プロパティが含まれている場合でも、新しい名前name: 'someothername'
が使用されます。
this.state.jasper
必ずしも最新の状態が含まれているわけではありません。の表記法を使用することをお勧めしますprevState
。
このソリューションを使用しました。
次のようなネストされた状態がある場合:
this.state = {
formInputs:{
friendName:{
value:'',
isValid:false,
errorMsg:''
},
friendEmail:{
value:'',
isValid:false,
errorMsg:''
}
}
}
現在のステータスをコピーして変更された値で再割り当てするhandleChange関数を宣言できます
handleChange(el) {
let inputName = el.target.name;
let inputValue = el.target.value;
let statusCopy = Object.assign({}, this.state);
statusCopy.formInputs[inputName].value = inputValue;
this.setState(statusCopy);
}
ここでは、イベントリスナーを含むhtmlです。状態オブジェクトに使用されているのと同じ名前を使用してください(この場合は 'friendName')
<input type="text" onChange={this.handleChange} " name="friendName" />
statusCopy.formInputs[inputName] = inputValue;
ここにはたくさんの答えがあることはわかっていますが、setStateの外に新しいオブジェクトのコピーを作成し、その後単にsetState({newObject})を作成しないことに驚いています。クリーンで簡潔、信頼できる。したがって、この場合:
const jasper = { ...this.state.jasper, name: 'someothername' }
this.setState(() => ({ jasper }))
または動的プロパティの場合(フォームに非常に役立ちます)
const jasper = { ...this.state.jasper, [VarRepresentingPropertyName]: 'new value' }
this.setState(() => ({ jasper }))
最初のケースは確かに構文エラーです。
コンポーネントの残りの部分は見えないので、ここでオブジェクトを自分の状態でネストしている理由を理解するのは困難です。オブジェクトをコンポーネント状態でネストすることはお勧めできません。初期状態を次のように設定してみてください:
this.state = {
name: 'jasper',
age: 28
}
そうすれば、名前を更新したい場合は、次のように呼び出すだけです。
this.setState({
name: 'Sean'
});
それはあなたが目指していることを達成しますか?
大規模で複雑なデータストアの場合は、Reduxなどを使用します。しかし、それははるかに高度です。
コンポーネントの状態に関する一般的な規則は、コンポーネントのUI状態(アクティブ、タイマーなど)を管理するためだけに使用することです。
これらの参照をチェックしてください:
別のオプション:Jasperオブジェクトから変数を定義して、変数を呼び出すだけです。
スプレッドオペレーター: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
}
})
シンプルでダイナミックな方法。
これでうまくいきますが、親がすべてのIDを親に設定して、親がオブジェクトの名前を指すようにする必要があります。つまり、id = "jasper"で、オブジェクトジャスパー内の入力要素の名前=プロパティに名前を付けます。 。
handleChangeObj = ({target: { id , name , value}}) => this.setState({ [id]: { ...this.state[id] , [name]: value } });
これで試すことができます:(注:入力タグの名前===オブジェクトのフィールド)
<input name="myField" type="text"
value={this.state.myObject.myField}
onChange={this.handleChangeInpForm}>
</input>
-----------------------------------------------------------
handleChangeInpForm = (e) => {
let newObject = this.state.myObject;
newObject[e.target.name] = e.target.value;
this.setState({
myObject: newObject
})
}
これはimmer immutabeユーティリティを使用した別のソリューションであり、深くネストされたオブジェクトに非常に適しているため、突然変異を気にする必要はありません。
this.setState(
produce(draft => {
draft.jasper.name = 'someothername
})
)
これで試すことができます:
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.name = 'someOtherName';
return {jasper: prevState}
})
または他のプロパティ:
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.age = 'someOtherAge';
return {jasper: prevState}
})
または、handleChage関数を使用できます。
handleChage(event) {
const {name, value} = event.target;
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState[name] = value;
return {jasper: prevState}
})
}
およびHTMLコード:
<input
type={"text"}
name={"name"}
value={this.state.jasper.name}
onChange={this.handleChange}
/>
<br/>
<input
type={"text"}
name={"age"}
value={this.state.jasper.age}
onChange={this.handleChange}
/>
age
内部のプロパティは失われjasper
ます。