React code locking in endless loop - no while loops involved

↘锁芯ラ 提交于 2019-12-13 14:50:33

问题


Am a bit new to React and wrote this code below. The component below is for rendering a Time and Date Picker for a tale. The time and date pickers only render for those social media where the tale is scheduled to appear.

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>
    )
  }
}

This renders a set of time and date pickers based on where the tale is to be displayed. Below is the component that is being displayed

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>
    )
  }
}

On selecting both the date and the time above. The entire page locks into an endless loop that caused the page to freeze. I am sure the functions are being calling each other in loop. But I do not know enough about React rendering to be able to figure out exactly why.


回答1:


In the componentDidUpdate check for the previous date and time state values before calling the function otherwise it will be called whenever the date and time are defined and the component is updating which it will do whenever you call the setSchedule function as it updates the state and parent which inturn leads to updated props being passed down to the child component.

Try

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)
        }
    }
  }

To confirm that any update in the parent component, the child components componentDidUpdate is called, have a look at this snippet

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'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>



回答2:


The reason is you are calling method setSchedule inside componentDidUpdate lifecycle method. setSchedule method is calling setState(). This resulting in a call to componentDidUpdate which subsequently calls setState again. you are creating an infinite loop because there's no break condition. you can call setState inside componentWillReceiveProps instead of 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.
    }
  }


来源:https://stackoverflow.com/questions/44713614/react-code-locking-in-endless-loop-no-while-loops-involved

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!