Itu adalah mungkin untuk memperbarui objek's properties dengan setState?
Sesuatu seperti:
this.state = {
jasper: { name: 'jasper', age: 28 },
}
Saya telah mencoba:
this.setState({jasper.name: 'someOtherName'});
dan ini:
this.setState({jasper: {name: 'someothername'}})
Hasil pertama dalam kesalahan sintaks dan kedua hanya tidak apa-apa. Ada ide?
Ada beberapa cara untuk melakukan hal ini, karena negara update operasi asinkron, jadi untuk memperbarui keadaan objek, kita perlu menggunakan fungsi updater dengan setState
.
1 - Sederhana satu:
Pertama membuat copy dari jasper
kemudian melakukan perubahan dalam:
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
})
Alih-alih menggunakan Objek.menetapkan
kita bisa juga menulis seperti ini:
let jasper = { ...prevState.jasper };
2 - Menggunakan [menyebar 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
}
}))
Catatan: Objek.menetapkan
dan Menyebar Operator
hanya menciptakan dangkal salin, jadi jika anda memiliki didefinisikan nested object atau array dari objek, anda membutuhkan pendekatan yang berbeda.
Asumsikan anda memiliki negara didefinisikan sebagai:
this.state = {
food: {
sandwich: {
capsicum: true,
crackers: true,
mayonnaise: true
},
pizza: {
jalapeno: true,
extraCheese: false
}
}
}
Untuk update extraCheese pizza objek:
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
}
}
}))
Mari kita asumsikan anda memiliki sebuah aplikasi todo, dan anda mengelola data-data di formulir ini:
this.state = {
todoItems: [
{
name: 'Learn React Basics',
status: 'pending'
}, {
name: 'Check Codebase',
status: 'pending'
}
]
}
Untuk update status setiap todo objek, menjalankan sebuah peta pada array dan memeriksa beberapa nilai yang unik dari setiap objek, dalam kasus kondisi=true
, kembali objek baru dengan diperbarui nilai, yang lain objek yang sama.
let key = 2;
this.setState(prevState => ({
todoItems: prevState.todoItems.map(
el => el.key === key? { ...el, status: 'done' }: el
)
}))
Saran: Jika obyek doesn't memiliki nilai yang unik, maka digunakan indeks array.
Ini adalah cara tercepat dan paling dapat dibaca dengan cara:
this.setState({...this.state.jasper, name: 'someothername'});
Bahkan jika ini.negara.jasper
sudah berisi nama tamu, nama baru nama: 'someothername'
dengan yang akan digunakan.
Saya menggunakan solusi ini.
Jika anda memiliki bersarang negara seperti ini:
ini.negara = { formInputs:{ friendName:{ nilai:'', isValid:false, errorMsg:'' }, friendEmail:{ nilai:'', isValid:false, errorMsg:'' } } }
anda dapat mendeklarasikan handleChange fungsi yang salin status dan kembali memberikan itu dengan mengubah nilai-nilai
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);
}
di sini html dengan acara pendengar. Pastikan untuk menggunakan nama yang sama digunakan dalam keadaan objek (dalam hal ini 'friendName')
<input type="text" onChange={this.handleChange} " name="friendName" />
Kasus pertama adalah memang sebuah kesalahan sintaks.
Karena saya dapat't melihat sisa komponen,'s sulit untuk melihat mengapa anda're bersarang benda-benda dalam negara anda di sini. It's bukan ide yang baik untuk sarang objek dalam komponen negara. Mencoba menetapkan keadaan awal menjadi:
this.state = {
name: 'jasper',
age: 28
}
Dengan cara itu, jika anda ingin update nama, anda hanya dapat menghubungi:
this.setState({
name: 'Sean'
});
Itu akan mencapai apa yang anda're bertujuan untuk?
Untuk yang lebih besar, lebih kompleks data toko, saya akan menggunakan sesuatu seperti Redux. Tapi yang's jauh lebih maju.
Aturan umum dengan komponen negara adalah untuk menggunakannya hanya untuk mengelola UI keadaan komponen (misalnya aktif, timer, dll.)
Memeriksa referensi ini:
Pilihan lain: menentukan variabel dari Jasper objek dan kemudian hanya memanggil variabel.
Menyebar 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
}
})
Saya tahu ada banyak jawaban di sini, tapi saya'm terkejut tidak satupun dari mereka membuat salinan objek baru di luar setState, dan kemudian hanya setState({newObject}). Bersih, ringkas dan dapat diandalkan. Jadi dalam hal ini:
const jasper = { ...this.state.jasper, name: 'someothername' }
this.setState(prevState => ({ jasper }))
Atau untuk properti dinamis (sangat berguna untuk bentuk-bentuk)
const jasper = { ...ini.negara.jasper, [VarRepresentingPropertyName]: 'nilai baru' } ini.setState(prevState => ({ jasper }))
Anda dapat mencoba dengan ini:
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.name = 'someOtherName';
return {jasper: prevState}
})
atau untuk properti lainnya:
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.age = 'someOtherAge';
return {jasper: prevState}
})
Atau anda dapat menggunakan handleChage fungsi:
handleChage(event) {
const {name, value} = event.target;
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState[name] = value;
return {jasper: prevState}
})
}
dan kode 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}
/>
Anda dapat mencoba dengan ini: (Catatan: nama masukan tag === bidang objek) `` <input name="myField" type="text" nilai={ini.negara.myObject.myField} onChange={ini.handleChangeInpForm}>
< input>handleChangeInpForm = (e) => { mari newObject = ini.negara.myObject; newObject[e.target.name] = e.target.nilai; ini.setState({ myObject: newObject }) } ``
Sederhana dan cara dinamis.
Ini akan melakukan pekerjaan, tetapi anda perlu untuk mengatur semua id ke orang tua sehingga orang tua akan mengarah ke nama objek, menjadi id = "jasper" dan nama-nama elemen input = properti di dalam objek jasper.
handleChangeObj = ({target: { id , name , value}}) => this.setState({ [id]: { ...this.state[id] , [name]: value } });
Tanpa menggunakan Async dan Menanti Menggunakan ini...
funCall(){
this.setState({...this.state.jasper, name: 'someothername'});
}
Jika anda menggunakan dengan Async Dan Menanti menggunakan ini...
async funCall(){
await this.setState({...this.state.jasper, name: 'someothername'});
}
Juga, berikut Alberto Piras solusi, jika anda don't ingin menyalin semua "negara" obyek:
handleChange(el) {
let inputName = el.target.name;
let inputValue = el.target.value;
let jasperCopy = Object.assign({}, this.state.jasper);
jasperCopy[inputName].name = inputValue;
this.setState({jasper: jasperCopy});
}
ini adalah solusi lain menggunakan immer immutabe utilitas, sangat cocok untuk sangat bersarang benda dengan mudah, dan anda tidak harus peduli tentang mutasi
this.setState(
produce(draft => {
draft.jasper.name = 'someothername
})
)