Is it at all possible to update object's properties with setState
?
Something like:
this.state = {
jasper: { name: 'jasper', age: 28 },
}
I have tried:
this.setState({jasper.name: 'someOtherName'});
and this:
this.setState({jasper: {name: 'someothername'}})
The first results in a syntax error and the second just does nothing. Any ideas?
You can try with this:
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.name = 'someOtherName';
return {jasper: prevState}
})
or for other property:
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState.age = 'someOtherAge';
return {jasper: prevState}
})
Or you can use handleChage function:
handleChage(event) {
const {name, value} = event.target;
this.setState(prevState => {
prevState = JSON.parse(JSON.stringify(this.state.jasper));
prevState[name] = value;
return {jasper: prevState}
})
}
and HTML code:
<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}
/>
Use spread operator and some ES6 here
this.setState({
jasper: {
...this.state.jasper,
name: 'something'
}
})
Also, following Alberto Piras solution, if you don't want to copy all the "state" object:
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});
}
try this,it should work fine
this.setState(Object.assign(this.state.jasper,{name:'someOtherName'}));
The first case is indeed a syntax error.
Since I can't see the rest of your component, it's hard to see why you're nesting objects in your state here. It's not a good idea to nest objects in component state. Try setting your initial state to be:
this.state = {
name: 'jasper',
age: 28
}
That way, if you want to update the name, you can just call:
this.setState({
name: 'Sean'
});
Will that achieve what you're aiming for?
For larger, more complex data stores, I would use something like Redux. But that's much more advanced.
The general rule with component state is to use it only to manage UI state of the component (e.g. active, timers, etc.)
Check out these references:
Your second approach doesn't work because {name: 'someothername'}
equals {name: 'someothername', age: undefined}
, so theundefined
would overwrite original age value.
When it comes to change state in nested objects, a good approach would be Immutable.js
this.state = {
jasper: Record({name: 'jasper', age: 28})
}
const {jasper} = this.state
this.setState({jasper: jasper.set(name, 'someothername')})
You can try with this: (Note: name of input tag === field of object)
<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
})
}
this is another solution using immer immutabe utility, very suited for deeply nested objects with ease, and you should not care about mutation
this.setState(
produce(draft => {
draft.jasper.name = 'someothername'
})
)
Try with this:
const { jasper } = this.state; //Gets the object from state
jasper.name = 'A new name'; //do whatever you want with the object
this.setState({jasper}); //Replace the object in state
I used this solution.
If you have a nested state like this:
this.state = {
formInputs:{
friendName:{
value:'',
isValid:false,
errorMsg:''
},
friendEmail:{
value:'',
isValid:false,
errorMsg:''
}
}
}
you can declare the handleChange function that copy current status and re-assigns it with changed values
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);
}
here the html with the event listener. Make sure to use the same name used into state object (in this case 'friendName')
<input type="text" onChange={this.handleChange} " name="friendName" />
This setup worked for me:
let newState = this.state.jasper;
newState.name = 'someOtherName';
this.setState({newState: newState});
console.log(this.state.jasper.name); //someOtherName
Another option: define your variable out of the Jasper object and then just call a variable.
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
}
})
This is the fastest and the most readable way:
this.setState({...this.state.jasper, name: 'someothername'});
Even if this.state.jasper
already contains a name property, the new name name: 'someothername'
with be used.
I know there are a lot of answers here, but I'm surprised none of them create a copy of the new object outside of setState, and then simply setState({newObject}). Clean, concise and reliable. So in this case:
const jasper = { ...this.state.jasper, name: 'someothername' }_x000D_
this.setState(() => ({ jasper }))
_x000D_
Or for a dynamic property (very useful for forms)
const jasper = { ...this.state.jasper, [VarRepresentingPropertyName]: 'new value' }_x000D_
this.setState(() => ({ jasper }))
_x000D_
Simple and dynamic way.
This will do the job, but you need to set all the ids to the parent so the parent will point to the name of the object, being id = "jasper" and name the name of the input element = property inside of the object jasper.
handleChangeObj = ({target: { id , name , value}}) => this.setState({ [id]: { ...this.state[id] , [name]: value } });
Without using Async and Await Use this...
funCall(){
this.setState({...this.state.jasper, name: 'someothername'});
}
If you using with Async And Await use this...
async funCall(){
await this.setState({...this.state.jasper, name: 'someothername'});
}
Source: Stackoverflow.com