Reactjs 从consumer componentDidMount更新react上下文会导致无限重渲染
我正在使用上下文API在React中尝试一些状态管理;我想要实现的是,当我到达一个特定的路由时,我从服务器加载数据,将其存储在上下文中,并在页面本身中显示它。这会导致一个无限循环,对服务器的请求会一次又一次地执行(而且永远不会停止) 我正在尝试为提供者和使用者逻辑使用高阶组件:Reactjs 从consumer componentDidMount更新react上下文会导致无限重渲染,reactjs,react-context,Reactjs,React Context,我正在使用上下文API在React中尝试一些状态管理;我想要实现的是,当我到达一个特定的路由时,我从服务器加载数据,将其存储在上下文中,并在页面本身中显示它。这会导致一个无限循环,对服务器的请求会一次又一次地执行(而且永远不会停止) 我正在尝试为提供者和使用者逻辑使用高阶组件: import React, { Component, createContext } from 'react'; import RequestStatus from '../RequestStatus'; import
import React, { Component, createContext } from 'react';
import RequestStatus from '../RequestStatus';
import { getData } from '../Api';
const dataCtx = createContext({
data: [],
getData: () => {},
requestStatus: RequestStatus.INACTIVE,
});
export default dataCtx;
export function dataContextProvider(WrappedComponent) {
return class extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
getData: this.getData.bind(this),
requestStatus: RequestStatus.INACTIVE,
};
}
async getData() {
this.setState({ requestStatus: RequestStatus.RUNNING });
try {
const data = await getData();
this.setState({ data, requestStatus: RequestStatus.INACTIVE });
} catch (error) {
this.setState({ requestStatus: RequestStatus.FAILED });
}
}
render() {
return (
<dataCtx.Provider value={this.state}>
<WrappedComponent {...this.props} />
</dataCtx.Provider>
);
}
};
}
export function dataContextConsumer(WrappedComponent) {
return function component(props) {
return (
<dataCtx.Consumer>
{dataContext => <WrappedComponent dataCtx={dataContext} {...props} />}
</dataCtx.Consumer>
);
};
}
我曾尝试为消费者从HOC切换到其他模式,但没有任何帮助:
import React, { Component } from 'react';
import RequestStatus from './RequestStatus';
import dataCtx from './contexts/DataContext';
class DataList extends Component {
async componentDidMount() {
const { getData } = this.context;
await getData();
}
render() {
const { data, requestStatus } = this.context;
return (
{/* display the data here */}
);
}
}
DataList.contextType = dataCtx;
export default DataList;
DataList只是我希望触发上下文更新的页面之一
我猜提供商导致了整个应用程序的重新呈现,但为什么?我哪里出了问题,如何解决这个问题?请求循环之所以发生,是因为
DataList
组件被重新渲染,调用ComponentDidMount
,在每次渲染后调用getData()
如果组件的道具或状态发生更改,组件将进行渲染
getData()
设置状态属性requestStatus
(这就是整个应用程序重新呈现的原因),它是DataList
的一个属性-导致重新呈现DataList
您不应该使用
requestStatus
作为DataList
的道具,因为您是从上下文中获取的。这可能是因为您的提供者(dataContextProvider
)级别函数getData
与从。/Api
导入的函数具有相同的命名空间
然后我相信当下面的行const data=await getData()时
在下面的代码块中运行,它实际上调用providersgetData
函数,从而导致循环
async getData() {
this.setState({ requestStatus: RequestStatus.RUNNING });
try {
const data = await getData();
this.setState({ data, requestStatus: RequestStatus.INACTIVE });
} catch (error) {
this.setState({ requestStatus: RequestStatus.FAILED });
}
}
好的,在尝试在沙箱中复制问题后,我意识到问题是什么:我在渲染函数中的HOC中包装父组件,如下所示:
<Route exact path="/datapage" component={requireLoggedInUser(Page)} />
这迫使
DataList
组件在每次重新呈现应用程序时被销毁并重新创建。我不确定你的意思,requestStatus
不是DataList
的道具,它是上下文的一部分,就像数据一样。此外,根据react文档,仅当组件添加到DOM树时,而不是每次渲染时,才应调用componentDidMount
。组件在任何时候都会离开DOM吗?我希望是这样,但事实似乎并非如此。。即使有不同的名字,我仍然能得到循环。嗯,很公平!我不知道还能是什么。其他一切似乎都很好。我建议一点一点地消除一些复杂性,这样你就可以缩小问题的范围。如果您使用项目的基本代码创建了一个,这样任何愿意提供帮助的人都可以通过沙箱调试问题,这也会很有帮助。关于沙箱的好主意,我将构建它并在帖子中编辑指向它的链接。。也许这也有助于发现问题:)
async getData() {
this.setState({ requestStatus: RequestStatus.RUNNING });
try {
const data = await getData();
this.setState({ data, requestStatus: RequestStatus.INACTIVE });
} catch (error) {
this.setState({ requestStatus: RequestStatus.FAILED });
}
}
<Route exact path="/datapage" component={requireLoggedInUser(Page)} />