我正在尝试使用Context API在React中进行一些状态管理;我想要实现的是,当我到达特定的路由时,我从服务器加载数据,将其存储在上下文中,并在页面本身中显示。这会导致一个无限循环,在该循环中,对服务器的请求一遍又一遍地完成(并且永不停止)。
我正在尝试将高阶组件用于提供者和使用者逻辑:
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>
);
};
}
提供者是App组件本身:
import React, { Fragment } from 'react';
import { dataContextProvider } from './contexts/DataContext';
import { userContextProvider } from './contexts/UserContext';
import AppRoutes from './AppRoutes';
function App() {
return (
<Fragment>
<main>
<AppRoutes />
</main>
</Fragment>
);
}
export default userContextProvider(dataContextProvider(App));
这是导致循环的使用者:
import React, { Component } from 'react';
import RequestStatus from './RequestStatus';
import { dataContextConsumer } from './contexts/DataContext';
class DataList extends Component {
async componentDidMount() {
const { dataCtx: { getData } } = this.props;
await getData();
}
render() {
const { dataCtx: { data, requestStatus } } = this.props;
return (
{/* display the data here */}
);
}
}
export default dataContextConsumer(DataList);
我曾尝试为消费者放弃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只是我要触发上下文更新的页面之一。
我猜测提供商正在导致整个应用程序的重新渲染,但是为什么呢?我在哪里出问题了,该如何解决?
答案 0 :(得分:1)
好吧,尝试在沙盒中复制问题之后,我意识到了问题所在:我将父组件包装在渲染函数内部的HOC中,如下所示:
<Route exact path="/datapage" component={requireLoggedInUser(Page)} />
这迫使DataList
组件在每次重新渲染应用时都被销毁并重新创建。
答案 1 :(得分:0)
之所以发生请求循环,是因为DataList
组件被重新渲染,调用了ComponentDidMount
,在每次渲染之后调用了getData()
。
如果组件的道具或状态发生更改,则组件将呈现。
getData()
设置状态属性requestStatus
(这是重新渲染整个应用程序的原因),它是DataList
的支持-导致{{1}的重新渲染}。
您不应该将DataList
用作requestStatus
的道具,因为无论如何都是从上下文中获取的。
答案 2 :(得分:0)
这可能是因为您的提供者(dataContextProvider
)级功能getData
与您从../Api
导入的功能具有相同的名称空间。
然后,我相信当下面的代码块中的以下行const data = await getData();
运行时,它实际上会调用提供程序getData
函数,从而导致循环。
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 });
}
}