Locking code code in infinite loop - no loops

A bit new to React and wrote this code below. The component below is for rendering Time and Date Picker for fairy tale. Collectors of time and date are displayed only for those social networks in which the fairy tale should 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 displays a set of time and date pickers based on where the fairy tale should be displayed. Below is the component that is 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>
    )
  }
}

      

When choosing a date and time. The whole page is blocked by an endless loop which caused the page to freeze. I'm pretty sure the functions are calling each other in a loop. But I don't know enough about React Rendering to understand exactly why.

+3


source to share


2 answers


In componentDidUpdate

check previous date and time state values

before calling the function, otherwise it will be called whenever the date and time is determined and the component is updated, which it will do whenever you call the function setSchedule

as its state and parent is updated, which causes the props to be updated. passed 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 parent component is being called child components componentDidUpdate

, see 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>
      

Run code


+1


source


The reason is that you are calling a method setSchedule

inside componentDidUpdate

a lifecycle method. setSchedule

method calls setState()

. This results in a call componentDidUpdate

, which is then called setState

again. you are creating an infinite loop because there is no interrupt condition. you can call setState internally componentWillReceiveProps

instead 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


source







All Articles