React Conditional Render Pattern
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:
- What's the different between these two ways?
- Is one of them better than the other?
- 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?
Answer
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.
Related Questions
- → How to update data attribute on Ajax complete
- → October CMS - Radio Button Ajax Click Twice in a Row Causes Content to disappear
- → Octobercms Component Unique id (Twig & Javascript)
- → Passing a JS var from AJAX response to Twig
- → Laravel {!! Form::open() !!} doesn't work within AngularJS
- → DropzoneJS & Laravel - Output form validation errors
- → Import statement and Babel
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM