Javascript 为什么我需要使用setState回调来设置依赖于第一项的第二个状态项的状态';什么是状态整理?
在这个componentDidUpdate方法中,在执行setState以将引号设置为从提取返回的内容之后,我必须使用回调第二次执行setState以将randomQuoteIndex设置为调用randomQuoteIndex的结果,这依赖于Javascript 为什么我需要使用setState回调来设置依赖于第一项的第二个状态项的状态';什么是状态整理?,javascript,reactjs,Javascript,Reactjs,在这个componentDidUpdate方法中,在执行setState以将引号设置为从提取返回的内容之后,我必须使用回调第二次执行setState以将randomQuoteIndex设置为调用randomQuoteIndex的结果,这依赖于this.state.quotes.length,即: componentDidMount() { fetch('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2e
this.state.quotes.length
,即:
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
})
}))
}
为什么下面的代码不起作用?根据所选的答案,我的印象是,在为第一项设置状态之后,才会应用setState中的第二项。如果我尝试这样做,我会得到一个错误“TypeError:无法读取undefined的属性'quote'”(我读到setState是异步的,关于何时使用回调,但我很难理解我读到的内容/它在这种情况下如何应用。)
以下是完整的组件代码(工作版本):
import React,{Component}来自'React';
导入“/App.css”;
从“lodash”导入{random};
从“./components/Button”导入按钮;
类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
报价:[],
randomQuoteIndex:null,
isDoneFetching:false
}
}
componentDidMount(){
取('https://gist.githubusercontent.com/nataliecardot/0ca0878d2f0c4210e2ed87a5f6947ec7/raw/1802a693d02ea086817e46a42413c0df4c077e3b/quotes.json')
//获取JSON响应字符串并将其解析为JS对象
.then(response=>response.json())
//状态设置为quotes:quotes由于解构
//使用setState回调,因为setState是异步的,并且需要确保在设置randomQuoteIndex状态之前加载引号,因为它依赖于它
.then(quotes=>this.setState({quotes},()=>{
这是我的国家({
randomQuoteIndex:this.randomQuoteIndex(),
isDoneFetching:正确
})
}))
}
获取随机引用(){
返回this.state.quotes[this.state.randomQuoteIndex];
}
randomQuoteIndex(){
返回random(0,this.state.quotes.length-1);
}
render(){
返回(
{this.state.isDoneFetching?this.randomQuote.quote:'正在加载…'}
);
}
}
导出默认应用程序;
并不是setState是异步的,而是在设置状态之前调用randomQuoteIndex
的结果。无论是否进行异步状态更新,都会出现这种情况。考虑这个稍微重构的版本<代码>组件DealStuts<代码>:
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
,并且(可能)为您保存一次重新渲染。就个人而言,我并不认为React的作者在setState
中回调的意图是使用它来调用下一个setState
。
为什么不试试上面提到的@Icepickle:
函数randomQuoteIndex(引号){
返回random(0,quotes.length-1);
}
...
...
.然后(引号=>{
这是我的国家({
引用,
randomQuoteIndex:randomQuoteIndex(引号),
isDoneFetching:正确
})
}))
...
仅更新一次状态=>确保始终只有一个渲染周期那么,回调将确保已应用上一个状态。问题是,为什么您的
randomQuoteIndex
依赖于一个状态属性,而不是检索一个数组作为一个参数,这将是一个更可重用的概念(当时它甚至不需要再位于组件内部),而错误来自于此?它是否发生在render()
中?我也不明白为什么您会依赖getter属性来检索引号,但随后请求引号的引号:)我猜罪魁祸首是回调中的this
引用。为了验证,您是否可以将randomQuoteIndex:this.randomQuoteIndex()
更改为类似于randomQuoteIndex:Date.now()
的其他内容,并查看这是否会产生相同的错误?您是否可以尝试在引号字段中使用prevState,就像在回答此问题时一样?如果我们想在setState中保留对象上的字段,我们需要使用prevState或spread运算符。您的建议奏效了,但我不明白如何在这个.randomQuoteIndex(引号)和这个.randomQuoteIndex()中,调用依赖于首先设置的引号的状态。我错过了什么?谢谢你的帮助!如果你看一下重构后的this.randomQuoteIndex(quotes)
,你会发现它实际上并没有在任何时候使用this.state
,quotes
被作为参数传入,这就是为什么它可以在setState
更新组件状态之前被调用的原因。我看到它没有使用this.state
,但我的困惑是,对于要调用的函数,它依赖于quotes
状态作为参数。但我现在明白了,这只是因为组件didmount
设置状态
中的所有内容都是立即应用的(甚至不是按顺序应用的),所以引号
状态是在设置状态
的这个.randomQuoteIndex(引号)
中作为参数需要的同时设置的。不管是谁,你知道为什么吗<
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)
})
}
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);
}