Reputation: 6587
As was pointed out to me in another question, if I have a function call without an argument in setState
, randomQuoteIndex()
, and the function uses a state set in that setState
, it's called before setState
.
componentDidMount() {
fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
.then(response => response.json())
.then(quotes => this.setState({
quotes,
randomQuoteIndex: this.randomQuoteIndex(),
isDoneFetching: true
}));
}
randomQuoteIndex() {
return random(0, this.state.quotes.length - 1);
}
This results in an error because the state of quotes
isn't available at the time of randomQuoteIndex()
call.
However, if I change randomQuoteIndex()
to instead use a passed in quotes
parameter, as below, it works.
componentDidMount() {
fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
.then(response => response.json())
.then(quotes => this.setState({
quotes,
randomQuoteIndex: this.randomQuoteIndex(quotes),
isDoneFetching: true
}));
}
randomQuoteIndex(quotes) {
return random(0, quotes.length - 1);
}
This is not what I expected; I had assumed that the state of quotes
would be available at the time randomQuoteIndex()
is called since it was called within setState
. Why is randomQuoteIndex()
called before setState
even though it's inside it?
Upvotes: 0
Views: 1054
Reputation: 4537
It is because setState
is an async operation. You can still use your original function by using setState
as a callback
componentDidMount() {
fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
.then(response => response.json())
.then(quotes => this.setState({
quotes,
isDoneFetching: true
}, () => {
this.setState({
randomQuoteIndex: this.randomQuoteIndex(),
}); //this callback will be executed after your state is updated.
}));
}
randomQuoteIndex() {
return random(0, this.state.quotes.length - 1);
}
So, essentially once a setState
function is performed, the updated values will only reflect after the update lifecycle is finished, which means you can get the values either in componentDidUpdate
method or by using the setState
function as a callback.
I wouldn't recommend this solution but in this case, the function randomQuoteIndex()
will get the updated state values without having any parameter passed.
Upvotes: 2
Reputation: 1292
Thats because at the time you passed the object to setState, you are executing inline call to this.randomQuoteIndex.
state.quotes did not exist yet in the state.
constructor() {
this.state = { quotes: [] };
}
componentDidMount() {
fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
.then(response => response.json())
.then(quotes => {
this.setState({
quotes,
randomQuoteIndex: this.randomQuoteIndex(),
isDoneFetching: true
})
});
}
randomQuoteIndex() {
return random(0, this.state.quotes.length - 1);
}
Upvotes: 1