【问题标题】:Calling setState() with child functional component causes infinite loop使用子功能组件调用 setState() 会导致无限循环
【发布时间】:2021-02-19 21:06:48
【问题描述】:

我正在使用react-week-scheduler 在我的页面上显示周历视图。该组件是基于类的父组件的功能子组件。我希望父组件管理日历上显示的事件的schedule 状态,并将其作为道具传递给子组件。

我面临的问题是,每次我对TimeGrid 进行调整(通过单击并拖出一个新事件块)并触发我的handleGridChange 函数以将该调整保存到schedule 状态字段,它会导致状态更新的无限循环,因为setState 导致子TimeGrid 组件更新,从而再次触发handleGridChange 函数,使我进入无限循环。

如果我直接在子组件上处理schedule 状态并使用useState 挂钩更新它,TimeGrid 组件可以正常工作,但是我的应用程序的其余部分无法访问schedule状态。我曾尝试将 TimeGrid 转换为基于类的组件,但后来我遇到了 setState 的其他问题,因为我不认为该组件是为这种方式设计的。

我对 react hooks 很陌生/不熟悉,所以我觉得这可能会导致这个问题的部分甚至全部。这也可能与TimeGrid 组件的设计方式有关,useEffect 在我设置状态时会不断改变事物,但我不确定也无法弄清楚。任何见解都会非常有帮助。

我的父组件看起来像这样:

import TimeGrid from './TimeGrid';

class ScheduleView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      schedule: [], // initially empty
    };
  )

  handleGridChange(newSchedule) {
    this.setState({
      schedule: newSchedule,
    });
  }

  render() {
    return (
      <TimeGrid
        schedule={this.state.schedule}
        handleGridChange={this.handleGridChange.bind(this)}
      />
    );
  }
}

我的TimeGrid 组件看起来像这样:

function TimeGrid(props) {
  // const [schedule, setSchedule] = useState([]); // <-- managing state with this works fine, but then I don't have access to it outside this component

  // oldHandleGridChange(newSchedule) {
  //   setSchedule(newSchedule);
  // }

  return (
    <TimeGridScheduler
      schedule={props.schedule}
      onChange={props.handleGridChange}
    />
  );
}

export default TimeGrid;

【问题讨论】:

  • 在构造函数上绑定函数,然后将函数传递给Child

标签: javascript reactjs


【解决方案1】:

需要在构造函数上绑定它,当函数绑定作为道具传递时,将创建一个新函数,道具将表示更改再次触发渲染

import TimeGrid from './TimeGrid';

class ScheduleView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      schedule: [], // initially empty
    };
    this.handleGridChange = this.handleGridChange.bind(this);
  )

  handleGridChange(newSchedule) {
    this.setState({
      schedule: newSchedule,
    });
  }

  render() {
    return (
      <TimeGrid
        schedule={this.state.schedule}
        handleGridChange={this.handleGridChange}
      />
    );
  }
}

【讨论】:

  • 这成功了!为什么我需要在构造函数上绑定它(为什么不是我的工作)?如果你用解释更新你的答案,我会接受。
  • 更新了@McFizz 的解释
【解决方案2】:

只需触发一次onChange 事件即可。或者简而言之,您可以使用粗箭头函数 ( => ) 绑定函数。

import TimeGrid from './TimeGrid';

class ScheduleView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      schedule: [], // initially empty
    };
  )

  handleGridChange = (newSchedule) => {
    this.setState({
      schedule: newSchedule,
    });
  }

  render() {
    return (
      <TimeGrid
        schedule={this.state.schedule}
        handleGridChange={(e) => this.handleGridChange(e)} 
        /* or handleGridChange={ this.handleGridChange } */
      />
    );
  }
}

【讨论】:

  • 这与我当前的实现有何不同?
  • 您在安装组件时调用 this.handleGridChange()。而不是您必须在触发某些事件时调用该函数,即在这种情况下 this.handleGridChange()
【解决方案3】:

这主要是因为onChange函数是无限时间触发的,你需要在那边添加箭头操作符。

此链接可能对您有所帮助 Prevent Infite loop

【讨论】:

    【解决方案4】:

    用这个代替你的 handleGridChange 函数

    <TimeGrid
            schedule={this.state.schedule}
            handleGridChange={(newSchedule) => this.setState({schedule: newSchedule})}
    />
    

    它肯定会起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-23
      • 2021-02-13
      • 1970-01-01
      • 2020-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多