React conditional render pattern

- 1 answer

Ad

I have implemented a Modal component that shows a modal dialog on the screen. Normally the modal will show conditionally. There are two ways that I can do this in the render function:

render(){
    ...
    <Modal show={this.state.showModal}>
        // something in modal
    </Modal>
}

In the Modal component, I use this.props.show to add a different class to itself. When this is false, it will add a display:none to hide the modal.

Another way is like this:

render(){
    ...
    { this.state.showModal &&
        (<Modal>
            // something in modal
        </Modal>)
    }
}

This uses showModal to decide whether or not to add the Modal in render.

What I want to figure out is:

  1. What's the different between these two ways?
  2. Is one of them better than the other?
  3. Is there another way to do this?

EDIT: It seems that different persons have different preference. For me myself, I prefer what @ErikTheDeveloper said. The ability that show/hide the Modal should keep inside the Modal, and when we don't need to show the Modal, we can return null in the Modal.

I think maybe there's not a certain answer for which way is better. Maybe it's just personal choice?

Ad

Answer

Ad

I answered a similar question a while back relating to the best way of opening/closing modal

I have spent a lot of time with React since then and learned a few lessons along the way.

I've found this general approach to work nicely for dealing with modals: Using a fully controlled "dumb" component that takes 3 props.

  • show: Boolean - Is the modal visible?
  • close: Function - The modal needs a callback in order to close itself
  • children: node - The contents of the modal

See React Docs for info on Controlled Components


To answer your question about the difference between the two, is that IMO option 1 provides a cleaner and more flexible API to work with while option 2 is more minimalist.

With option 1 you could take care of hiding/showing by using either CSS or returning null from <Modal>. I would recommend returning null since the modal contents will simply not be rendered vs. rendering them and "hiding" them via CSS.

Option 2 forces the more verbose "JSX way" of conditionally rendering which I think is appropriate in many cases. However I feel like the concept of a modal merits the hiding/showing being a part of a <Modal> components API (props/methods/etc...)


Why pass down the close prop/callback?

Considering most modals have UX such as closing on events such as: pressing [ESC], clicking "x", clicking outside the modal, etc... a modal needs to be informed of how to "close itself" via passing down the close prop/callback in my examples below.


Code Examples

// The simple, fully controlled Modal component
const Modal = React.createClass({
  render() {
    const {
      show,     // Boolean - Is the modal visible?
      close,    // Function - The modal needs a function to "close itself"
      children, // node - The contents of the modal 
    } = this.props;
    return !show ? null : (
      <div className="some-class-for-styling">
        <a onClick={close}>x</a>
        {children}
      </div>
    );
  }
});

const UsesModal = React.createClass({
  setEditing(editing) {
    this.setState({editing});
  },

  render() {
    // `editing` could come from anywhere. 
    // Could be derived from props, 
    // or managed locally as state, anywhere really....
    const {editing} = this.state;
    return (
      <div>
        <h1>Some Great Component</h1>
        <a onClick={() => this.setEditing(true)}>Show Modal!</a>
        <Modal show={editing} close={() => this.setEditing(false)}>
          Some great modal content... show based on UsesModal.state.editing
        </Modal>
      </div>
    );
  }
});

And if you want to let the modal manage its own state, you can wrap up the "dumb" modal with a slightly smarter component and make use of refs and "public component methods" (although I've found that sticking with the simplified approach usually results in less headache and regret ;))

const SmarterModal = React.createClass({
  close() {
    this.setState({show: false});
  },

  open() {
    this.setState({show: true});
  },

  render() {
    const {children} = this.props;
    const {show} = this.state;
    return (
      <Modal show={show} close={this.close}>
        {children}
      </Modal>
    );
  }
});

const UsesSmarterModal = React.createClass({
  render() {
    return (
      <div>
        <h1>Some Great Component</h1>
        <a onClick={() => this.refs.my_smarter_modal.open()}>Show Modal!</a>
        <SmarterModal ref="my_smarter_modal">
          Some great modal content... show based on SmarterModals own internal state
        </SmarterModal>
      </div>
    );
  }
});

There are a number of ways you can wrap up the simple <Modal>, but I feel like it serves as a solid foundation and the data flow plays nicely to allow computing/deriving "is the modal open" from wherever makes the most sense. This is the approach I've found to work nicely.

Ad
source: stackoverflow.com
Ad