无限循环中的反应代码锁定 - 不涉及循环

时间:2017-06-23 05:21:53

标签: javascript reactjs ecmascript-6 material-ui

对React来说有点新,并在下面编写了这段代码。下面的组件用于渲染故事的时间和日期选择器。时间和日期选择器仅为那些计划出现故事的社交媒体呈现。

class TaleScheduler extends Component {
  constructor(props) {
    super(props);
    this.state = {
      returnData: {},
      totalNeeded: numberOfChannels(this.props.data)
    };
  }
  setSchedule = (date, channel) => {
    const returnData = update(this.state.returnData, {
      $merge: {channel: date}
    })
    this.setState({returnData: returnData})
    const { data, ScheduleTale } = this.props
    if (Object.values(this.state.returnData).length === this.state.totalNeeded) {
      FireAction(this.state.returnData, data.id)
    }
  }
  render() {
    const { data } = this.props
    return (
      <div style={{"display": "inline-block"}}>
        {data.showOnFacebook ? (<DateTimePicker data={data} image={facebook} setSchedule={this.setSchedule} />) : null}
        {data.showOnTwitter? (<DateTimePicker data={data} image={instagram} setSchedule={this.setSchedule} />) : null}
        {data.showOnInstagram ? (<DateTimePicker data={data} image={twitter} setSchedule={this.setSchedule} />) : null}
        {data.showOnApp ? (<DateTimePicker data={data} image={app} setSchedule={this.setSchedule} />) : null}
        <FlatButton label="Schedule" onClick={this.setSchedule} />
      </div>
    )
  }
}

这会根据故事的显示位置呈现一组时间和日期选择器。下面是正在显示的组件

class DateTimePicker extends Component {
  constructor(props) {
    super(props);
    this.state = {
      date: null,
      time: null
    };
  }
  handleDateInput = (event, date) => {
    this.setState({
      date: date
    })
  }
  handleTimeInput = (event, time) => {
    this.setState({
      time: time
    })
  }
  componentDidUpdate(prevProps, prevState) {
    const {setSchedule, channel} = this.props
    if (this.state.date && this.state.time) {
      setSchedule(concatenateDateAndTime(this.state.date, this.state.time), channel)
    }
  }
  render() {
    return (
      <List>
        <ListItem
        leftAvatar={
          <img src={this.props.image} style={styles.scheduledChannelImgStyle} />
        }>
        </ListItem>
        <ListItem>
          <DatePicker onChange={this.handleDateInput} />
        </ListItem>
        <ListItem>
          <TimePicker onChange={this.handleTimeInput} />
        </ListItem>
      </List>
    )
  }
}

选择上面的日期和时间。整个页面锁定一个无限循环,导致页面冻结。我确信这些函数正在循环中相互调用。但我不太了解React渲染能够弄清楚原因。

2 个答案:

答案 0 :(得分:1)

原因是您在setSchedule生命周期方法中调用方法componentDidUpdatesetSchedule方法正在调用setState()。这导致拨打componentDidUpdate,随后再次呼叫setState。你正在创建一个无限循环,因为没有中断条件。您可以在componentWillReceiveProps内调用setState而不是componentDidUpdate

  componentDidUpdate(prevProps, prevState) {
    const {setSchedule, channel} = this.props
    if (this.state.date && this.state.time) {
      setSchedule(concatenateDateAndTime(this.state.date, this.state.time), channel)//Calling method that calls setstate.
    }
  }

答案 1 :(得分:1)

在调用函数之前componentDidUpdate检查previous date and time state values,否则每当定义日期和时间并且组件正在更新时,只要你调用{{1函数,因为它更新状态和父元素,其中inturn导致更新的道具传递给子组件。

尝试

setSchedule

要确认调用子组件componentDidUpdate(prevProps, prevState) { const {setSchedule, channel} = this.props if(prevState.date !== this.state.data || prevState.time !== this.state.time) { if (this.state.date && this.state.time) { setSchedule(concatenateDateAndTime(this.state.date, this.state.time), channel) } } } 的父组件中的任何更新,请查看此代码段

&#13;
&#13;
componentDidUpdate
&#13;
class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            clicked: false
        }
    }
    render() {
        return (
            <div>
                <Child />
                <button onClick={() => this.setState((prevState) => ({clicked: !prevState.clicked}))} > Toggle</button>
             </div>
        )
    } 
}

class Child extends React.Component {
   componentDidUpdate(prevProps, prevState) {
       console.log('update in child called');
   }
    render() {
        return (
            <div>
                Hello Child
             </div>
        )
    } 
}
ReactDOM.render(<Parent/>, document.getElementById('app'));
&#13;
&#13;
&#13;