Show or hide element in React
Solution 1:
React circa 2020
In the onClick
callback, call the state hook's setter function to update the state and re-render:
const Search = () => {
const [showResults, setShowResults] = React.useState(false)
const onClick = () => setShowResults(true)
return (
<div>
<input type="submit" value="Search" onClick={onClick} />
{ showResults ? <Results /> : null }
</div>
)
}
const Results = () => (
<div id="results" className="search-results">
Some Results
</div>
)
ReactDOM.render(<Search />, document.querySelector("#container"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
JSFiddle
React circa 2014
The key is to update the state of the component in the click handler using setState
. When the state changes get applied, the render
method gets called again with the new state:
var Search = React.createClass({
getInitialState: function() {
return { showResults: false };
},
onClick: function() {
this.setState({ showResults: true });
},
render: function() {
return (
<div>
<input type="submit" value="Search" onClick={this.onClick} />
{ this.state.showResults ? <Results /> : null }
</div>
);
}
});
var Results = React.createClass({
render: function() {
return (
<div id="results" className="search-results">
Some Results
</div>
);
}
});
ReactDOM.render( <Search /> , document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
JSFiddle
Solution 2:
<style type="text/css">
.hidden { display:none; }
</style>
const Example = props =>
<div className={props.shouldHide? 'hidden' : undefined}>Hello</div>
Solution 3:
Here is an alternative syntax for the ternary operator:
{ this.state.showMyComponent ? <MyComponent /> : null }
is equivalent to:
{ this.state.showMyComponent && <MyComponent /> }
Learn why
Also alternative syntax with display: 'none';
<MyComponent style={this.state.showMyComponent ? {} : { display: 'none' }} />
However, if you overuse display: 'none'
, this leads to DOM pollution and ultimately slows down your application.
Solution 4:
Here is my approach.
import React, { useState } from 'react';
function ToggleBox({ title, children }) {
const [isOpened, setIsOpened] = useState(false);
function toggle() {
setIsOpened(wasOpened => !wasOpened);
}
return (
<div className="box">
<div className="boxTitle" onClick={toggle}>
{title}
</div>
{isOpened && (
<div className="boxContent">
{children}
</div>
)}
</div>
);
}
In code above, to achieve this, I'm using code like:
{opened && <SomeElement />}
That will render SomeElement
only if opened
is true. It works because of the way how JavaScript resolve logical conditions:
true && true && 2; // will output 2
true && false && 2; // will output false
true && 'some string'; // will output 'some string'
opened && <SomeElement />; // will output SomeElement if `opened` is true, will output false otherwise (and false will be ignored by react during rendering)
// be careful with 'falsy' values eg
const someValue = [];
someValue.length && <SomeElement /> // will output 0, which will be rednered by react
// it'll be better to:
someValue.length > 0 && <SomeElement /> // will render nothing as we cast the value to boolean
Reasons for using this approach instead of CSS 'display: none';
- While it might be 'cheaper' to hide an element with CSS - in such case 'hidden' element is still 'alive' in react world (which might make it actually way more expensive)
- it means that if props of the parent element (eg.
<TabView>
) will change - even if you see only one tab, all 5 tabs will get re-rendered - the hidden element might still have some lifecycle methods running - eg. it might fetch some data from the server after every update even tho it's not visible
- the hidden element might crash the app if it'll receive incorrect data. It might happen as you can 'forget' about invisible nodes when updating the state
- you might by mistake set wrong 'display' style when making element visible - eg. some div is 'display: flex' by default, but you'll set 'display: block' by mistake with
display: invisible ? 'block' : 'none'
which might break the layout - using
someBoolean && <SomeNode />
is very simple to understand and reason about, especially if your logic related to displaying something or not gets complex - in many cases, you want to 'reset' element state when it re-appears. eg. you might have a slider that you want to set to initial position every time it's shown. (if that's desired behavior to keep previous element state, even if it's hidden, which IMO is rare - I'd indeed consider using CSS if remembering this state in a different way would be complicated)
- it means that if props of the parent element (eg.
Solution 5:
with the newest version react 0.11 you can also just return null to have no content rendered.
Rendering to null