Deelux
Deelux

Reputation: 1195

Why does this cause an endless loop? I don't understand

At the moment the code does what I want it to do but it also crashes my application. I think it's because of an endless loop but I am not sure. I want the code to check the two variables, if one equals the other, I want to change the state of the modal.

newTimestamp gets renewed every second based upon the seconds passed in ReactPlayer.

How can I prevent an endless loop in this situation?

This is my code:

import React, { Component } from 'react';
import { Modal, Button, Tooltip, Link, ControlLabel } from 'react-bootstrap';


export class CommentsModalAdmin extends Component {
   constructor(props) {
    super(props);
    this.state = {
      showModal: false,
    };

    this.close = this.close.bind(this);
    this.open = this.open.bind(this);
  }

  componentWillReceiveProps(props){
    const newTimestamp = this.props.newTimestamp;
    const timestamp = this.props.comment.timestamp;
    if (newTimestamp === timestamp ){
      this.setState({ showModal: true });
      this.props.stopVideo();
    }
  }


  close() {
    this.setState({ showModal: false });
    this.props.playVideo();
  }

  open() {
    this.setState({ showModal: true });
    this.props.stopVideo();


  }

  render() {
    const { newTimestamp, city, person, location, title, content, fileLink, timestamp } = this.props.comment;



    return (
      <div className="flex">
        <a onClick={this.open}><span className="modal-bg"><span style={{ height: rand }} className="modal-color" ></span></span></a>

        <Modal show={this.state.showModal} onHide={this.close} bsSize="lg">
          <Modal.Header closeButton>
            <Modal.Title >{title}</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <p><ControlLabel>Tagged city: </ControlLabel> {city}</p>
          <p><ControlLabel>Tagged person: </ControlLabel> {person}</p>
          <p><ControlLabel>Tagged location: </ControlLabel> {location}</p>
          <p><ControlLabel>Tagged image: </ControlLabel></p>
          <img src={fileLink} width="100%"/>
          <ControlLabel>Tagged content: </ControlLabel> <div dangerouslySetInnerHTML={{__html: content}} />


          </Modal.Body>
          <Modal.Footer>
            <Button onClick={this.close}>Close</Button>
          </Modal.Footer>
        </Modal>
      </div>
    );
  }
}

These are the error messages I see: "Uncaught RangeError: Maximum call stack size exceeded"

And

"Warning: performUpdateIfNecessary: Unexpected batch number (current 3200, pending 1783"

I found that adding this.props.stopVideo(); caused the loop but I don't understand why. Anyone able to explain?

Upvotes: 1

Views: 909

Answers (2)

Deelux
Deelux

Reputation: 1195

I managed to solve this by adding an extra if/else condition like this:

  componentWillReceiveProps(nextProps){
    const newTimestamp = this.props.newTimestamp;
    const timestamp = this.props.comment.timestamp;
    if(nextProps !== this.props){
      if(this.state.showModal === false){
        if (newTimestamp === timestamp ){
          this.setState({ showModal: true });
          this.props.stopVideo();
        } 
      }
    }
  }

Hope it can help anyone with a simular problem.

Upvotes: 0

Fabian Schultz
Fabian Schultz

Reputation: 18546

You're using the componentWillReceiveProps method. This method is executed every time the component receives new (or any) props. Inside that method you trigger a function that gets called in the parent of the component, which in return, triggers another function that utilizes setState.

componentWillReceiveProps(props) {
  // ...
  this.props.stopVideo();
}

setState causes a re-render, and therefore also the CommentsModalAdmin is re-rendered and componentWillReceiveProps is called. This results in the loop.

You might want to revise that method (or check if the props actually changed with something like props == this.props).

Upvotes: 3

Related Questions