Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: hiding vs removing components [closed]

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

like image 803
Ivan Adanenko Avatar asked Sep 01 '21 07:09

Ivan Adanenko


People also ask

Are React components self closing?

Note: Every React component can be self-closing: <div /> . <div></div> is also an equivalent.

How do you hide a component in React without unmounting?

{display: 'none'} does not unmount the component. It works fine for me.

Should I unmount component?

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.

Does React render hidden component?

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.


7 Answers

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

  1. Simplicity - As you know JSX has been optimised for reactively toggling markup, so it will not print 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' }} />
  1. 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.

  2. 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.

  3. 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.

  4. 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.

like image 160
Stefan J Avatar answered Oct 21 '22 08:10

Stefan J


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

TL;DR

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

  • SEO - if you render conditionally some navigation pannel/dialog, that holds links pointing to other pages of your app, those links won't appear in your DOM, hence can't be traversed by crawler and indexed, which won't be the case if you toggle visibility with style settings;
  • UX - if according to design there has to be animation (e.g. fade in/out) of UI element appearing/disappearing on screen, if you use conditional rendering, you might need more advanced techniques to make sure animation still works not to frustrate your users
like image 33
Yevgen Gorbunkov Avatar answered Oct 21 '22 10:10

Yevgen Gorbunkov


Some facts

  • Code to pixel is a multi-step process. It's generally expected, javascript to take around 10-12ms to maintain 60fps.
  • Premature optimization is a bad idea. So measure -> optimize -> measure -> repeat.

The short answer depends. Some possible scenarios.

Fetching(API, img, video)

  • Usually ends up fetching even before the user visits the page.
  • For eg the below img would be fetched even before the user visit the page and the same goes for any API request.
     <div style={{ display: "none" }}>
        <img src="https://picsum.photos/200/300" />
      </div>
  • So if you are API heavy or image-heavy takes a note of it. There is a way to prevent this behaviour but isn't possible in order version.
  • Also, you could prefetch asserts based on priority if asserts are the only reason why you prerender.

Animation

  • It's already been posted multiple times but there is an easy and elegant solution. write a wrapper(HOC preferred) around the actual component and let it have both display none for an empty div and conditional rendering for the actual component. So if you want to animate boom you are good to go.

Performance

  • In code to pixel conversion, JS takes a significant time especially for the very first time of code running. Refer JS engine internals Start here
  • So if you execute cat page JS with a display none property while the user wants to see a dog page good luck retaining the user.
  • On the other hand, if you were successful doing with less or no performance hit please post your method I would love to read it.
  • Ideally, you could use SSR with prefetching the HTML to solve this issue as well, since it just flushes out RAW HTML user just needs to render that in the browser which is equivalent to changing display property.
  • On the other hand, if you just use it to render some static pages changing the display property is probably ok but it's debatable on why 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.

like image 27
ChandraKumar Avatar answered Oct 21 '22 09:10

ChandraKumar


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

like image 28
Nikan dlv Avatar answered Oct 21 '22 09:10

Nikan dlv


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>
  );
}
like image 45
Samuel Newman Avatar answered Oct 21 '22 08:10

Samuel Newman


"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.

like image 21
Phil Avatar answered Oct 21 '22 08:10

Phil


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.

like image 28
rexdev0211 Avatar answered Oct 21 '22 08:10

rexdev0211