【问题标题】:react componentdidupdate provokes infinite loopreact componentdidupdate 引发无限循环
【发布时间】:2015-11-04 15:12:42
【问题描述】:

我使用onChange 触发对elasticsearch 的API 调用,以便提示自动完成列表。 为了确保我的商店在重新渲染之前更新,我添加了 componentDidMount ,这样我就不会落后了。但切入正题需要代码,所以:

constructor(props) {
  super(props)
  this.state = {
    inputValue: '',
    options: []
  };
  this.props = {
    inputValue: '',
    options: []
  };
  this._onChange = this._onChange.bind(this);
}

componentDidMount() {
  CodeStore.addChangeListener(this._onChange);
}

_onChange(event) {
  if (this.state.inputValue && !event) {
    var enteredChars = this.state.inputValue;
    console.log('NO EVENT!');
  } else if (event.target.value) {
    console.log('EVENT!');
    var enteredChars = event.target.value;
    this.setState({inputValue: enteredChars});
  }
  CodeService.nextCode(enteredChars);
}

如您所见,我添加了一些日志事件只是为了确保我的状况正常。我读到setState 会引发重新渲染,因此它在条件内,但并没有停止循环。并且控制台日志确认条件切换。但是在我的条件中包含setState 会阻止功能并且我没有得到列表。

这是我的日志:

                        0
Home.jsx:48             EVENT!
Home.jsx:50             0
CodeService.js:27       request
CodeActions.js:10       dispatch
CodeStore.js:22         store
Home.jsx:43             1
Home.jsx:46             NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27       request
CodeActions.js:10       dispatch
CodeStore.js:22         store
Home.jsx:43             1
Home.jsx:46             NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27       request
CodeActions.js:10       dispatch
CodeStore.js:22         store
Home.jsx:43             1
Home.jsx:46             NO EVENT!

无论如何,无限循环不会损害性能。我认为是因为componentWillUnmount,但必须避免大量的 API 调用。希望这些信息足以作为任何证据。

【问题讨论】:

    标签: javascript reactjs infinite-loop


    【解决方案1】:

    看起来无限循环是由以下模式引起的:

    1. 用户类型输入
    2. _onChange 更新状态 + 触发存储操作
    3. 自行存储更新并发送更改事件
    4. 商店更改事件触发相同 _onChange 事件
    5. _onChange 不会更新状态,但仍会触发存储操作
    6. 转到第 3 步并重复(无限期地)

    修复步骤:

    • 为用户输入和存储更新创建不同的更改处理程序(@Janaka Stevens 已经建议)
    • 将存储中的数据置于状态
    • 用户输入不必处于状态(如果您的反应代码没有为输入字段提供值,它将以空值开始,并保留任何输入的内容)

    那么您的代码可能如下所示:

    constructor(props) {
      super(props)
      this.state = {
        options: []
      };
      // removed the this.props bit: props should not be updated inside component
      this._onChangeUser = this._onChangeUser.bind(this);
      this._onChangeStore = this._onChangeStore.bind(this);
    }
    
    componentDidMount() {
      CodeStore.addChangeListener(this._onChange);    // this is OK
    }
    
    _onChangeUser(event) {
      console.log('EVENT!');
      var enteredChars = event.target.value;
      CodeService.nextCode(enteredChars);
      // No need to update state here - go to sleep until store changes
    }
    
    _onChangeStore() {
      var newList = getListFromStore();  // your own function to get list from store
      this.setState({ options: newList});            // update state here
    }
    

    不确定您所说的“落后一滴”是什么意思,或者可能是什么原因造成的,但清理无限循环是一个不错的起点;)

    PS:以上代码仅为草图,可能有错别字。

    【讨论】:

    • 哦,太好了,这真的帮助了我:)。我稍后会在这里发布结果。你有什么资源可以提供来深入了解 React 的使用吗?
    • 不客气。至于来源:React's own pages 是一个很好的来源。我特别推荐观看视频。
    【解决方案2】:

    您的输入事件和存储侦听器似乎都在使用 _onChange。他们需要单独的方法。

    【讨论】:

    • 没错。即使有一个单独的,当我将函数添加到构造函数时,它也会产生一个无限循环,但是从构造函数中删除它会给我带来与以前相同的行为,我可以在日志中看到我有一个 10 的数组,但视图渲染时没有.我会将构造函数添加到问题中
    • 如果存储监听器使用_onChange和_onChange使用CodeService和CodeService触发器存储和存储触发器onChange和onChange触发器CodeService和...
    • 好吧,这很清楚:/ 无限循环刚刚涵盖了它不是一个真正的解决方案,我有一个输出。然后,我将搜索需要包含的内容以处理重新渲染事件。谢谢!
    • 另外:最好避免在同一块/函数中在this.setState() 之后执行任何操作。由于setState() 触发重新渲染(即放弃当前块或函数),因此您在同一块中的 setState 之后编写的任何语句(在您的情况下为 `CodeService.nextCode(enteredChars);`)最多会产生不可预测的结果。
    • @wintvelt 很高兴知道谢谢!但不幸的是,它并没有改变行为。您还有其他提示componentDidMount 的外观吗?如果需要更多信息,我会添加!
    猜你喜欢
    • 2021-08-26
    • 2021-07-12
    • 2018-06-07
    • 2016-10-22
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多