tajo / react-portal

🎯 React component for transportation of modals, lightboxes, loading bars... to document.body or else.
MIT License
2.14k stars 169 forks source link

Using state to conditionally render components causing PortalWithState modal to close when closeOnOutsideClick true #222

Open davidjamescarter opened 5 years ago

davidjamescarter commented 5 years ago

I have found that when using the PortalWithState with closeOnOutsideClick my modal will close when using state to conditionally render components.

PortalWithState closeOnOutsideClick closeOnEsc defaultOpen>
    {({ closePortal, portal }) =>
        portal(
        <Modal closePortal={closePortal} key="confirmation-modal">
            <JobPreviewModal
            bid={bid}
            jobOffer={jobOffer}
            schedule={schedule}
            taxonomiesByClassification={taxonomiesByClassification}
            />
        </Modal>,
        )
    }
</PortalWithState>`
class JobPreviewModal extends PureComponent {
  state = {
    editing: false,
    some: false,
  };

  toggleEditingState = () => {
    this.setState(previousState => {
      return {
        editing: !previousState.editing,
        some: !previousState.some,
      };
    });
  };

  render() {
    const { jobOffer, bid, schedule, taxonomiesByClassification } = this.props;

    const { editing } = this.state;

    return !editing ? (
      <JobPreview
        bid={bid}
        jobOffer={jobOffer}
        schedule={schedule}
        taxonomiesByClassification={taxonomiesByClassification}
        toggleEditingState={this.toggleEditingState}
      />
    ) : (
      <h1>Editing</h1>
    );
  }
}
class Modal extends Component {
  render() {
    const { children, closePortal, small } = this.props;

    console.log('children', children);
    return (
      <ModalWrapper small={small}>
        <div>
          {children.length
            ? children.map(child => React.cloneElement(child))
            : React.cloneElement(children)}
          <button className="close" onClick={closePortal}>
            Close
          </button>
        </div>
      </ModalWrapper>
    );
  }
}

Changing state to edit: true. Causes modal to close.

Has anyone else experienced, have a fix? Going to see if I can figure out a fix locally and PR if so.

mikkelwf commented 5 years ago

I've found setting closeOnOutsideClick and triggering openPortal doesn't open the portal at all..

mikkelwf commented 5 years ago

@davidcarter-me i might have a solution for you.

When you click stuff inside the portal, changing state on a parent element causes a render on the click target. When this event bubbles to the Portal, the contains check inside the portals closeOnOutsideClick cannot reference the e.target

I worked around this by wrapping the state changing method in requestAnimationFrame, so the closeOnOutsideClick resolver runs first, and then the state change.

Hope that helps