Reputation: 13703
I'm trying to increment my state variable, but whenever I do so an error pops up which says that the variable state is undefined. I defined my variable inside the constructor. Obviously something is going on in the setState function.
Here is the code which renders an error:
displayDiv(){
var arr=[];
if (this.state.flag[2]){
this.setState({counter:counter+4}); // error:undefined
for (let i = this.state.counter-4; i < this.state.counter; i++)
arr.push(this.state.arrayHeader[0].content);
}
}
return(
arr.map(function(item,i){
return (
<div className="bodydiv col-sm-3">
<Header/>
<Content/>
<Tags/>
</div>
);
})
);
}
Here is the defined variable inside the constructor:
constructor(props){
super(props);
this.state = {
arrayHeader:[],
arraytag1:[],
arraytag2:[],
counter:0,
flag:[false,false,false]
}
}
Upvotes: 4
Views: 7116
Reputation: 2147
To add to the other good answers:
In short, you probably want something like this to be safe:
this.setState((prevState) => ({
...prevState, counter: prevState.counter+4
}));
Yes, your current problem was due to the undefined local variable counter
in this statement:
this.setState({ counter: counter+4 });
A simple solution (as pointed out by other answers already) is to refer to the respective state variable:
this.setState({ counter: this.state.counter+4});
As pointed out by cdaiga
, you'd probably want to preserve the other properties on your state since setState()
is replacing the current state with the parameter provided to it and you'd effectively loose all other values on it. You could do it like this:
this.setState({ ...this.state, counter: this.state.counter+4 });
As per the React Documentation, you should also take the asynchronous nature of setState()
into account.
React may batch multiple
setState()
calls into a single update for performance.Because
this.props
andthis.state
may be updated asynchronously, you should not rely on their values for calculating the next state.For example, this code may fail to update the counter:
// Wrong this.setState({ counter: this.state.counter + this.props.increment, });
To fix it, use a second form of
setState()
that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:// Correct this.setState((prevState, props) => ({ counter: prevState.counter + props.increment }));
We used an arrow function above, but it also works with regular functions
In your specific example, we would end up with something like this (as already stated at the top):
this.setState((prevState) => ({
...prevState, counter: prevState.counter+4
}));
Additional side note: due to this asynchronous nature of this.setState()
, accessing this.state
after calling this.setState()
will still return its old value. Your original posted code is accessing this.state.counter
immediately afterwards:
this.setState({counter:counter+4}); // error:undefined
for (let i = this.state.counter-4; i < this.state.counter; i++)
arr.push(this.state.arrayHeader[0].content);
}
Fortunately in this case you're not using the variable i
inside the loop and the this.state.arrayheader[0].content
is not being updated, i.e. the following would be equivalent:
this.setState((prevState) => ({
...prevState, counter: prevState.counter+4
}));
for (let i = 0; i < 4; i++) {
arr.push(this.state.arrayHeader[0].content);
}
Upvotes: 3
Reputation: 1606
I think its simple, try this in function displayDiv
this.setState({counter: this.state.counter+4});
you forgot the this.state at this line :)
Upvotes: 3
Reputation: 4937
You can replace:
this.setState({counter:counter+4}); // error:undefined
with:
const { counter } = this.state; // getting the counter from state
this.setState({counter:counter+4});
But then hope you really want to flush out all the other attributes of the state. Else you should do:
const { counter } = this.state;
this.setState(Object.assign({},this.state,{counter: counter + 4}));
See how to use Object.assign() method
Upvotes: 1
Reputation: 32797
Your counter +4
points nowhere.
It should be this.state.counter + 4
Also, if you are calling this function on the render()
make sure it has been previously binded, you can do that like this on the constructor:
this.displayDiv = this.displayDiv.bind(this);
Upvotes: 9