React components not mounting

1.1k views Asked by At

I recently upgraded to React v 16.5 and have been getting issues with some of my components. I'm showing one of them below that use to work before on 16.4.1. It's a simple download icon that renders a dropdown when state isOpen is true and will close its dropdown if you're clicking outside of it.

I keep receiving

Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the DownloadIcon component.

The stack trace points to this.setState({ isOpen: false }) in this.handleOutsideClick. I'm confused because I MOUNT logs although isMounted (which I just added for debugging purposes) does not actually get set to true.

class DownloadIcon extends React.Component {


static propTypes = {
    chartPanelEl: PropTypes.any,
    metricId: PropTypes.string,
    datasets: PropTypes.array,
    downloadFormats: PropTypes.array,
    metadata: PropTypes.any,
    tableHeaders: PropTypes.array,
    segments: PropTypes.array
  };

  state = {
    isOpen: false,
    isMounted: false // for debugging purposes
  };

  dom = React.createRef();

  componentDidMount() {
    console.log("I MOUNT"); // logs
    this.setState({ isMounted: true });
    window.addEventListener("click", this.handleOutsideClick, true);
  }

  componentWillUnmount() {
    window.removeEventListener("click", this.handleOutsideClick, true);
  }

  /**
   * Click listener to determine state of dropdown
   * @param {Object} e - event object
   */
  handleOutsideClick = e => {
    const target = e.target;
    const validTargets = [this.dom.current].concat(
      ...this.dom.current.children
    );

    if (this.dom && this.dom.current && validTargets.includes(target)) {
      return;
    }

    this.setState({
      isOpen: false
    });
  };

  /**
   * Handle click of download icon container to set open state
   * @param {Object} e - event object
   */
  handleClick = e => {
    this.setState({ isOpen: !this.state.isOpen });
  };

  render() {
    const dropdownClassNames = "dropdown " + (this.state.isOpen ? "open" : "");

    return (
      <div
        className="download-icon__container"
        onClick={this.handleClick}
        ref={this.dom}
      >
        <img className="download-icon" src={downloadIcon} />
        <div className={dropdownClassNames}>
          <div
            id="drop"
            data-toggle="dropdown"
            role="button"
            aria-haspopup="true"
            aria-expanded="false"
            href="#"
          />
          <ul id="menu1" className="dropdown-menu" aria-labelledby="drop">
            <li className="dropdown-title">Download as</li>
            {this.renderDownloadOptions()}
          </ul>
        </div>
      </div>
    );
  }

When I click on the download icon now, the console throws the warning and fails to render the dropdown. Any help would be appreciated on why this warning keeps showing up and why it may be breaking functionality!

0

There are 0 answers