在这个componentDidUpdate方法中,在执行setState以将引号设置为从获取中返回的内容后,我必须再次使用回调执行setState来将randomQuoteIndex设置为调用randomQuoteIndex的结果,该结果依赖于{{1} },即:
this.state.quotes.length
为什么下面的代码不起作用?根据对this question的选定答案,我的印象是setState中的第二个项目要等到第一个项目的状态设置好之后才能应用。如果尝试此操作,则会收到错误“ TypeError:无法读取未定义的属性'quote'”。 (我读到setState是异步的,关于何时使用回调,但是我很难理解在这种情况下我读到的内容/如何应用。)
componentDidMount() {
fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
// Takes a JSON response string and parses it into JS object
.then(response => response.json())
// state is set to quotes: quotes due to destructuring
// Using setState callback since setState is asynchronous and need to make sure quotes is loaded before setting the randomQuoteIndex state since it depends on it
.then(quotes => this.setState({ quotes }, () => {
this.setState({
randomQuoteIndex: this.randomQuoteIndex(),
isDoneFetching: true
})
}))
}
这是完整的组件代码(工作版本):
componentDidMount() {
fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
// Takes a JSON response string and parses it into JS object
.then(response => response.json())
// Using setState callback since setState is asynchronous and need to make sure quotes is loaded before setting the randomQuoteIndex state since it depends on it
.then(quotes => this.setState({
quotes,
randomQuoteIndex: this.randomQuoteIndex(),
isDoneFetching: true
}));
}
答案 0 :(得分:1)
并非setState是异步的,这是在设置状态之前调用randomQuoteIndex
的结果。有或没有异步状态更新都会是这种情况。考虑一下componentDidMount
的此重构版本:
componentDidMount() {
fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
.then(response => response.json())
.then(quotes => {
const newState = {
randomQuoteIndex: this.randomQuoteIndex(),
isDoneFetching: true,
quotes
}
this.setState(newState)
})
}
在功能上与您在问题中发布的版本完全相同。希望这可以突出显示this.randomQuoteIndex()
在this.setState(newState)
之前进行求值,并且由于尚未调用setState
,因此randomQuoteIndex
没有依赖的状态。调用setState
时,必须先对参数进行求值,然后才能将其传递给setState
,无论是否同步,在调用randomQuoteIndex
时更新都不会停留。
解决此问题的简单方法是使randomQuoteIndex
将引号列表作为参数,而不是将其从组件状态中拉出来。重写后,这对方法可能看起来像:
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);
}
只需要调用setState
一次,(可能)可以节省重新渲染的时间。
答案 1 :(得分:1)
我个人并不真的认为React的作者对setState
中的回调的意图是使用它来调用下一个setState
。
为什么不尝试上面提到的@Icepickle之类的东西:
function randomQuoteIndex(quotes) {
return random(0, quotes.length - 1);
}
...
...
.then(quotes => {
this.setState({
quotes,
randomQuoteIndex: randomQuoteIndex(quotes),
isDoneFetching: true
})
}))
...
您只更新一次状态=>确保您始终只有一个渲染周期