Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
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
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
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' }} />
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
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
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.
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.
I'm working on a small web application and I'm developing it using ReactJS and Material UI. In the examples provided in the documentation many components seems to have useStyles within the code. I followed the examples and now I basically a useStyles function within each of my components. My question is: is it good practice?
Usually I have a separate CSS file with all the classes, and frankly I find it easier to manage, but for this case I wanted to follow the CSS-in-JS pattern.
You can see an example of the code I'm working on here: https://github.com/sickdyd/foriio/blob/master/src/components/body/UserProfile.js
Thank you for any clarification you may can give me.
Yes, that is good practice.
It allows you to separate your concerns and localize your styles, where they are needed. You do not accidentally override styles while working on other classes. This will help you especially for larger projects.
It will also allow code splitting and only the CSS/CSS-in-JS that is needed and actually used will be downloaded and added to your website. This will improve your initial paint time as well since less CSS has to be parsed.
I you feel that you are repeating your code at several location, you could also share the useStyles functions or override the global theme to reduce the overall amount of code as well.
I am developing a web app and I want to use CSS grid layout. After few hours, I figured out most of my layouts were incorrect because the style was overwritten by lower component, losing gridArea. I had just been lucky it had worked so far.
Because I believe it's the container's responsibility to place items, items should be agnostic of whatever gridArea the upper component decides to assign them. Moreover, I have factories of components so I sometimes just don't know which item will be there. I am now doing this boilerplate in all my components:
<div style={{ ...props.style, ...styles.ThisComponent }}>
my item content...
</div>
What is the correct way of doing it? Any pitfall?
I am rewriting all my components now, please save me a lot of efforts!
CSS grid is only supported by the most recent browsers.
Wouldn't you prefer using Grid layout from material-ui? Then you can adjust everything. Here's a link if you do, there's also a CSS Grid layout exanplation there.
Hard-coding the styles property in all the components you will ever write like above seems to be an overkill. Also, using a fallback for browsers without CSS-Grid support should also be a priority.
Have you tried creating wrappers in styled-components and then putting your component code inside ? Could potentially save you the trouble if all the outer divs should have the same style ? The syntax may change a bit from what you have written, but seems more maintainable*
*might be opinionated
I'm working on a hybrid application for which I need a toolbar. This toolbar must handle different forms and functionalities, in some cases contains a title, other buttons and links and in others an autocomplete, then my questions is if is more efficient to build a dynamic component that accepts all these elements or work on different toolbar's that will be inserted and removed from the DOM as needed.
Thanks!
A dynamic toolbar will be faster, because angular wont need to re-render the whole toolbar each time it changes. It's smart enough just to find the stuff it needs to update.
Also it will make your code easier to maintain I think. Having multiple toolbars, probably with some shared logic/elements will cause repeated code.
Also you will probably have less lines of code with a dynamic toolbar, perhaps slightly reducing the size of your project. I suspect that wont be significant. Honestly, I think the biggest advantage wont be speed but cleaner, more maintainable code in general.
It depends on whether you are using lazy loading or bundling your entire App in one main.bundle.js
In the first case, you want to ship the strict minimum to the browser as it's needed. Therefore, you want separate component for each use case.
In the second case, it makes your app lighter to create on single component to handle different toolbar use cases.
To demonstrate this, (assuming you're not using lazy loading) you can create a small project with a main component which uses 2 different views.
In one case you create a single component for each view.
In the other you combine both views in one component.
Then build and serve both and you can see the difference in the weight of your JS files.
Hope this helps
I'm making this search component that I can just load using javascript and have it work wherever I load it. The idea is that it does an AJAX-search, so I don't want to code that up every time I put one on the page.
So maybe on pages that I want to put it on that would look like this:
var searchBox = new Search(inputBox);
Ideally, I wouldn't really want to have to link a style sheet everytime I do this. I'm just wondering if performance takes a big hit if I just create tags and add attributes like this:
$('<div></div>').css({
'background-color': #002323, etc.
});
I feel like its only slightly more verbose, but it will be much easier to manage and use.
Or do you know a better way of doing this?
Maybe this question is brushing the surface of a bigger problem, which is about making CSS object-oriented. I don't want it messing up other things on the page if there are css attributes with the same name. Everything else I do is object-oriented. Are there any CSS solutions or methodologies for this?
Two things come into mind:
If you ever want to change the style, you will have to do it in javascript, possibly at several places.
Obviously, applying styles one by one instead of just adding a class is slower.
CSS was designed to make your life easier and honestly I think it wouldn't be very wise to not to use it, unless you have some javascript style framework that does a better job.
It seems to me that it rather depends on how much CSS you need to apply to this search component, and whether you need to be able to skin it for different sites. Assuming your javascript is all held in one external file, is it a big problem to create a basic CSS file to go with it, and use the script to dynamically insert a <link> to the CSS file above other <link> elements in the document?
That way you can reuse and skin it very easily, overriding the styles set in the default CSS for any particular site just by adding the appropriate selectors to that site's stylesheet. If you set them all with jQuery, it'll be much harder to change the skin.
The main problems of your search component are obstrusive JS and probably non-accessible tool (except if you took the ARIA road).
The one you're talking about is secondary.
You should use carefully named classes, I wonder what can be easier to manage than a class="warning" (background-color: #FE0114; ? no way)