Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 从consumer componentDidMount更新react上下文会导致无限重渲染_Reactjs_React Context - Fatal编程技术网

Reactjs 从consumer componentDidMount更新react上下文会导致无限重渲染

Reactjs 从consumer componentDidMount更新react上下文会导致无限重渲染,reactjs,react-context,Reactjs,React Context,我正在使用上下文API在React中尝试一些状态管理;我想要实现的是,当我到达一个特定的路由时,我从服务器加载数据,将其存储在上下文中,并在页面本身中显示它。这会导致一个无限循环,对服务器的请求会一次又一次地执行(而且永远不会停止) 我正在尝试为提供者和使用者逻辑使用高阶组件: import React, { Component, createContext } from 'react'; import RequestStatus from '../RequestStatus'; import

我正在使用上下文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>
    );
  };
}
我曾尝试为消费者从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()时
在下面的代码块中运行,它实际上调用providers
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 });
      }
    }

好的,在尝试在沙箱中复制问题后,我意识到问题是什么:我在渲染函数中的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)} />