Home > Mobile >  React: hiding vs removing components [closed]
React: hiding vs removing components [closed]

Time:09-18

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

CodePudding user response:

On one hand, hidden DOM elements are ignored while building render tree, so the only performance gain you may possibly get may be caused by building DOM tree ahead of time.

On the other hand, excessive DOM size may slow down your browser unnecessarily.

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.

So, my personal opinion, 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, I would opt for conditional rendering.

p.s. one more (non-performance related) consideration should be taken into account, when you use conditional rendering to toggle visibility you may face certain difficulties animating (like fade in/out) your component kick in

CodePudding user response:

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.

CodePudding user response:

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.

CodePudding user response:

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

CodePudding user response:

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>
  );
}

CodePudding user response:

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

CodePudding user response:

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.

  • Related