This question is about architecture more than coding.
Here's the case. In React sometimes we want to hide components. For example, when user opens new page in SPA, when some toast is closed, etc. We can hide them with adding display: none
. Or we can remove them from the virtual DOM.
// Hidden div
<div style={{ display: 'none' }}/>
// Removed div
{false && <div/>}
And some of our seniors othen use the first variant. Even if they hide entire page. That's what they say about this method: "This case React prerenders needed content, so when the content must appear, it takes less time".
But in this case we can't use lifecycle hooks, because even when component hides, it's not removed. But the main problem as I think, is that real DOM becomes gigantic. And that's brings slowness, isn't it?
So, what is better?
I didn't found any conversations about this question. Maybe you could help me.
EDIT 1: Despite the fact there are some answers I'd like to know more opinions. So, I decided to open up a bounty
Note: Every React component can be self-closing: <div /> . <div></div> is also an equivalent.
{display: 'none'} does not unmount the component. It works fine for me.
ReactJS – componentWillUnmount() Method This method is called during the unmounting phase of the React Lifecycle, i.e., before the component is destroyed or unmounted from the DOM tree. This method is majorly used to cancel all the subscriptions that were previously created in the componentWillMount method.
A react component can contain elements, and you can even create components that show and hide with the use of css. But for most components, unless specifically built in as functionality, to show or hide them you will need to conditionally render them.
Let's compare some of the differences between these two methods for toggling HTML element visibility, element toggling (aka display: none|block
) and JSX short circuit rendering
false
, true
, null
and undefined
, hence you can write shorter logics in there. Similar case for not using template literals instead of JSX was brought by Facebook https://facebook.github.io/jsx/#why-not-template-literals. Simplicity leads to maintainability, in the long run it will help your app not become another spaghetti nonsense. isShown && <div />
vs
<div style={{ display: isShown ? 'block' : 'none' }} />
Performance - Spanning way more nodes is never good for performance and memory usage, generally it varies per application. It can be benchmarked using Chrome's Performance Monitor or the React Profiler. But more importantly React builds new performance optimisations around the knowledge that you would follow https://reactjs.org/docs/jsx-in-depth.html rather than using other tricks. Given that some or most of your codebase is using the element toggling
approach and there is a new version of React with performance improvements chances are you will probably spend weeks into refactoring to benefit from it.
Bugs - With JSX short circuit rendering you must remember not to use something like elements.length && elements.map(({ text }) => text)
as given that the elements
array has no members, JSX will print 0 instead of nothing. On the other side setting visibility with display: block
almost certainly will lead to flex
, inline
, inline-block
, table
elements to be set to block
. The second bug is harder to find as you need to deal with css styles or css-in-js.
Consistency - Given that JSX short circuit rendering is the recommended method by the maintainers of React it will be present in most React projects. But say you mix it with the old school display toggling method and any new developers joining the team will question why you are using both. Mixing these will most probably lead to bugs as well where an element might be shown by JSX and in the same time hidden with display: none
or vice versa.
Debugging - using React Devtools or Elements while having lots of elements being set to display: none
is a nightmare as it will be polluted with nodes that you simply don't need there
I reckon senior devs are used to toggle elements with display
as it is considered old school. It might also be a legacy of converting your app from jQuery to React. It was the only way of making UIs back in the days. Some habits or shall I say mental models are quite sticky. Now days in a React project I will consider the above a hack.
I would advice against using any other way of toggling visibility of markup in React but the standard JSX short circuit rendering isShown && <div />
. In my long experience of writing React apps I try to stick to the simplest and most expressive code, that all developers from uni graduates, to juniors, to seniors would expect as per best practices and wouldn't have trouble reading, so they reuse rather than write the nth version of the same component.
EDIT: As it was mentioned in other answers, transition animations are usually done with react-transition-group package that is only working with JSX short circuit rendering.
Note: to those, not interested in long-winded explanations (in attempt to score rep bounty), followed by irrelevant examples and conspiracies, here's a quick one
You need to bear in mind the following to make your own decision, depending on your specific use case:
Hidden DOM elements are ignored while building render tree, so the only performance gain you may possibly see when control visibility by styling, may be caused by building DOM tree ahead of time.
When visibility is controlled by style settings, excessive DOM size may slow down your browser unnecessarily.
On the other hand, from React prospective, applying conditional rendering (and rebuilding the tree of descendants, once you decide to make them visible) seems to be slightly more expensive than changing single attribute.
Considering the above, for complex components (large DOM subtree) with relatively high odds of being visited (or being shown most of the time over the course of user interactions) it would make sense to toggle visibility styling. Otherwise, conditional rendering seems to be a better option from performance standpoint.
p.s: Other than performance you may be concerned with
The short answer depends
. Some possible scenarios.
<div style={{ display: "none" }}>
<img src="https://picsum.photos/200/300" />
</div>
react
in the first place.So in a general sense personally I would prefer conditional rending unless if the odds of visiting the whole page is high as @Yevgen Gorbunkov stated.
Well if you want to use lifecycles there are workarounds for that as well. if you are using functional components then you can manage the rerenders using the dependency props.
Its true dom size can slow you down if you use it excessively https://web.dev/dom-size/ But is better if those components are constantly being updated rather then rendering a new component on demand.
If its a list of items and its gigantic i suggest you to take a look at https://react-window.vercel.app/#/examples/list/fixed-size or https://bvaughn.github.io/react-virtualized/#/components/List
Personally, I prefer to remove, but that then prevents fade out animations. I like to use something like this to get the benefits of both.
const FadeContainer = ({ show: showProp, children }) => {
const [show, setShow] = useState(showProp);
const timeoutRef = useRef();
useEffect(() => {
if (showProp) {
setShow(true);
} else {
timeoutRef.current = setTimeout(() => setShow(false), 500);
}
return () => clearTimeout(timeoutRef.current);
}, [showProp])
return show && (
<div style={{ opacity: showProp ? 1 : 0, transition: "opacity 0.5s ease" }}>
{children}
</div>
);
}
"It depends" is an answer to a lot of questions.
This discussion has also popped up within the Frontend team I am part of at work. A few things were taken into consideration over the time.
With React routing is mostly handled on the client side, giving you a lot of flexibility on how to handle the rendering of components and pages.
Does the site you work on have an extensive landing page, maybe with very few and small other pages? Then I suspect the additional DOM elements and HTML file size initially fetched and loaded into the DOM have little impact. Making them invisible with styling is perfectly fine.
Does the site have very many pages, and is it unlikely that the visitor is going to ever visit the vast majority of these? Then it would have a number of downsides hiding all those extra DOM elements with css. Think initial load time, the assets needing to be fetched can grow noticeably. In that case implementing code-splitting for different routes is probably a good idea, making hiding elements no longer an option.
A middle ground is also very possible here. It could make sense to code-split based on the (sub)routes your site has. But using css to hide elements like modals, elements that pop up when hovering over something, etcetera. So that everything within that page is snappy.
Like mentioned in other answers, using a prop to set visibility is a good approach to make fade ins and fade outs (which is of course harder) possible. Samuels answer is a nice proposal. Otherwise React Transition Group is used in my team to set classed based on transition states, allowing to animate the element in and out as well as removing the component from the DOM if you want.
I think this is an interesting question and hope to be able to hear more opinions from others too.
I think both have advantages and disadvantages.
Please see this article. Compare the performance between hiding React components with css and state management
Hiding components using display CSS property will be faster in toggling show and hide.
Removing components using non-CSS way, when conditional state value is false
, it has one less component to rerender, so that it improves performance.
Which is better depends on your choice of your project.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With