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.
source to share
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>
source to share
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.
}
}
source to share