ReactJS:多个集合状态异步发生,状态未更新



在触发位于渲染中的函数(filterAndSort(之前,面临状态未更新的问题。我在函数中添加了一个控制台.log语句,并且只更新了其中一个状态。我的代码对我来说似乎是合乎逻辑的,因为我设置了一个 if 条件,其中函数仅在 setState 发生后触发

完整的错误消息:

警告:无法在未挂载的设备上调用 setState(或强制更新( 元件。这是一个无操作,但它表明您的内存泄漏 应用。若要修复,请取消所有订阅和异步任务 在组件将卸载方法中。

但是,我怀疑这是因为我有多个 setState 异步发生。

我在想,也许,只有在获取所有 axios 请求后,我才需要重写 componendDidMount 以为所有变量设置状态。 多个公理请求进入 ReactJS 状态

我认为另一种解决方案是将函数的返回结果存储为状态而不是变量,然后添加一个组件DidUpdate。

componentDidUpdate(prevProps, prevState) {
if (this.state.value > prevState.value) {
this.filterAndSort();  
}
}

元件

class Results extends Component {
constructor(){
super()
this.state = {
results: [],
races: [],
arr = []
isLoading: true
};
}
componentDidMount(){
const oneRequest = axios.get(URL_ONE)
.then(response =>
response.data.data.map(result => ({...
))
)
.then(results => this.setState({results, isLoading: false}))    
const twoRequest = axios.get(URL_TWO)
.then(response =>
response.data.data.map(race => ({...}))
)
.then(races => this.setDefault(races))
}
setDefault = (races) => {
........
this.setState({arr, races, isLoading:false})
}
filterAndSort = (races, results) => {
console.log(races, results)
.......
}
render() {
const{races, results} = this.state
if (isLoading == true) {
return (
<div>
<p>Loading...</p>   
</div>
)
} else {
return (
<div>
<BarChart 
qualData={this.filterAndSort(races, results)} 
raceData={this.filterAndSort(races, results)} 
width="1200" 
height="500" />
</div>
);
}
}
}
export default Results;

嗯,我想到了很多事情。

首先,仅当您有两条数据之一(以先到者为准(时,才将 isLoad 设置为 false,因此 render 方法将在某个时候使用空竞赛或结果调用您的函数。 另一件事,您正在异步调用 setState。当请求完成时,您的组件可能不再存在,因此它将尝试更新不存在的组件并因该错误而失败。

对于第一个问题,一种可能的解决方案是为结果和比赛设置两个 isLoading 变量。

对于第二个问题(在未挂载组件上调用的 setState(,它有点复杂,因为您需要以某种方式取消请求。我建议阅读更多关于此的内容,一般建议是使用 redux 等库将数据移出组件。如果你谷歌cancel promise on unmount你会发现关于这个问题的讨论。你也可以使用"isMounted"变量来处理它,它将作为一个丑陋的补丁工作。

因此,一旦请求一(或两个(完成,就会调用 setState,然后重新呈现组件。isLoading 现在是真的,所以 filterAndSort 被调用与结果(或比赛(,但不能同时调用两者,因为第二个请求仍然挂起。

最后,在您的渲染方法中,需要首先定义您的 isLoad(我认为它在您的代码中没问题,但在问题中不行(,并且 is True 比较可以更好地作为

if (isLoading) {而不是if (isLoading == True) {

你是对的。当提出多个请求时,最佳做法始终是等待它们全部解决,然后再继续。为此,您可以使用 ES6 中内置的Promise库。此外,据我所知,获取数据的最佳做法是在componentWillMount()中执行此操作。我还要补充一点,this的上下文在异步函数中会发生变化。所以在你的componentWillMount()

let promiseArr = [axios.get(URL_ONE), axios.get(URL_TWO)];
let _this = this;
Promise.all(promiseArr)
.then((resp) => {
// Call _this.setState() here. Response from URL_ONE  
// will be available in resp.data[0] and URL_TWO in resp.data[1]
}).catch((err) => {
console.log(err);
})

此外,在您的构造函数中:

constructor(){
super()
this.state = {
results: [],
races: [],
arr = []
isLoading: true
};
this.setDefault = this.setDefault.bind(this);
this.filterAndSort = this.filterAndSort.bind(this);
}

使用.bind确保在调用这些方法时,this的上下文引用到类的当前实例。

我认为在做完这些事情之后,错误就会消失。希望有帮助。

最新更新