Ariel Rodriguez Romero

Hiding state, simplifying modal dialogs usages

Similarly to lifting state up, in some scenarios you might not care how a piece of state is managed. Like for example, a modal dialog with an isOpen property that decides if the dialog is open or not. react-modal works like this:

<Modal isOpen={true}>
  <div>... modal dialog content here</div>
</Modal>

This offers a great deal of flexibility, but a problem arises, whenever you need to use this modal component you’ll also need to add logic to control whether the dialog is open or not. One solution could be creating a base class for all modal dialogs and manage the isOpen state there, but inheritance is usually not recommended in React. There’s a better way.

It should be possible to extract the logic that controls the isOpen property from the content of the dialog and the component that takes care of launching it. This seems like a good use case for render props. The following ModalManager is a possible solution, it has a property component that returns a button or whatever element is responsible for displaying the modal. And the children property, also a render prop, will return the content of the modal.

<ModalManager
  component={showModal => <button onClick={showModal}>Show Modal</button>}
>
  {({ hideModal }) => (
    <div>
      <h1>Modal content</h1>

      <button onClick={hideModal}>Hide modal</button>
    </div>
  )}
</ModalManager>

This will make using a modal dialog easier since it’s completely abstracted from all the logic concerned with the state of the modal dialog. Assuming we have a separate Modal component (like the one provided by react-modal), implementing ModalManager is simple.

class ModalManager extends React.Component {
  state = {
    modalOpen: false
  };

  showModal = () => this.setState({ modalOpen: true });

  hideModal = () => this.setState({ modalOpen: false });

  render() {
    return (
      <React.Fragment>
        {this.props.component(this.showModal)}
        <Modal isOpen={this.state.modalOpen} onRequestClose={this.hideModal}>
          {this.props.children({
            hideModal: this.hideModal
          })}
        </Modal>
      </React.Fragment>
    );
  }
}

Here’s the basic example from react-modal modified to use ModalManager.

See the Pen Sample: ModalManager, hiding state with render props by Ariel Rodriguez Romero (@arielsvn) on CodePen.


This class is used several times in refinebio, there ModalManager has other properties to support more use cases. I should also thank ramenhog since we came up with this together.

Render props are a very powerful technique in React, I can’t stop using it now that I learned about it. The first person I heard mention it was Michael Jackson, one of the creators of react-router.


Related posts

Deploying a serverless NextJS App

We migrated to NextJS recently and started using ZEIT to deploy our frontend. We required some configuration and even found a bug on ZEIT’s platform in the process.

Set up end-to-end tests with jest-pupeteer and NextJS

This contains details and the configuration files required to setup jest-pupeteer for end-to-end testing in a NextJS app.

Get route information from Google Flights

Simple strategy to scrape information from google flights (with manual work). It’s helpful if you don’t need a lot of information.