basement blog

3 things you should stop doing when server-side rendering react (or any UI layer)

hello 👋. it me and i'm back again with another list. someone on reddit said it bothered them that my last list contained 4 points instead of a more round number like 3 or 5, so here's a list of 3 to make everyone happy. if you're not happy and would like to discuss, please DM me here and i'll ask my parents if it's okay to use the computer.

this list is a culmination of some things i've learned while working on basement community. things that i think you, the Web developer, should leave behind when working on a server-side rendered app (which i will shorten to "SSR app" going forward) using a UI layer like React.

1. using CSS-in-JS libraries

stop using CSS-in-JS or any component library that uses one. working on a team, you might be familiar with libraries like Styled Components or Material-UI. they have been widely adopted because they're pretty amazing. they allow teams of developers to get started writing UI quickly and can give you a cohesive look-and-feel to your site with a minimal amount of work.

while they were infinitely useful when the original craze happened around React and Vue and other client-side rendered library, these CSS-in-JS libraries are bad for SSR sites because all that JavaScript responsible for applying your styles to the DOM elements has to executed twice: once on the server and once on the client. and what that means is that the user has to download a bunch of JavaScript they normally wouldn't need, which defeats the whole point of writing a SSR app. well okay it doesn't defeat the whole point but you're not taking full advantage of the benefits SSR gives you when you adopt a library that does this.

here's a snapshot of the JavaScript that is downloaded when visiting basement community. as you can see, it's about 850kB of resources and after taking a glance through the files, I'd say about 100kB are related to components i wrote using Styled Components and the actual library code itself:

basement community javascript downloads

you can make a case that the size isn't that big, but this 100kB came after i realized my mistake and have been working to remove Styled Components in favor of actual CSS. this download size and execution time could be much worse had i relied on the library more across the site. But the point here is that you don't need this - it's adding redundancy and asking more from your users' batteries and potentially wasting their time. instead, use vanilla CSS or a CSS pre-processor that compiles to CSS so that users get a faster and more performant experience.

if you need more convincing i recommend reading this article which highlights some other reasons for getting rid of this coding pattern, but for the sake of time, let's move on.

2. storing data in state management libraries

one really tempting pattern to establish early on in writing a website is managing state that needs to be accessed across your codebase - think users or account settings. these shared pieces of state typically are used to determine whether or not to show some UI or perform some conditional logic or route people to certain URLs over others. stop thinking about re-storing this information on the client - just have the server give you all the information you need for the specific page and be done there. no more Redux. no more Vuex. no more state management libraries.

why? well take a look at this screenshot here. basement community is currently getting a user from the server once the app initially loads. the React code is then storing the user information at the top-most-level in a React Context. then finally, the client is determining if the user is an admin-level user and showing a "new forum" link to navigate to the create forum page for admin users only.

basement community page load test

notice anything interesting about that .gif? it's that the "new forum" link loaded after everything else on the page did. that's because i made the mistake of storing my user information in a client-side store and because of that, HTML elements like the "new forum" link can't be rendered correctly on the server because it doesn't have access to the React Context.

here's another example - i'm rendering a datetime on the server, but then using the user's account settings that are stored in the same React Context on the client to adjust the datetime to the user's preferred timezone, and what happens as a result is that the datetime will change before your eyes. watch the date change from "12:32 am" to "2:32 pm":

datetime changing

again, this is totally unnecessary. the server could have easily requested the account settings and rendered it right the first time. luckily though, it's not so much of a problem on the site. i only employed this strategy in a few places, so it's relatively easy to remove and do the right way, but learn from my mistake!

3. using window breakpoint checks to render UI

something i see all the time both professionally and on my own projects is the jump to create a utility function that checks the window size and render DOM elements conditionally based on whether the user is on a mobile or desktop screen. with SSR apps, this becomes a slight issue because the server is never going to know what screen size the user is on because it doesn't have access to that information. and since the website is being rendered once on the server and once on the client, both renders become inconsistent when you start introducing conditional elements based on window size.

for the user, this doesn't mean much - they still get the same experience. but from a performance perspective, it can become more expensive if your server and client HTML tree don't match. this is mostly due to the fact that client-side libraries like React look for differences in the component tree to update the screen, and if React is finding differences from what it was given from the server and what it thinks it should be rendering, the client-side React will do extra work to re-render elements unnecessarily. which in so many words is just more JavaScript executing when it shouldn't.

what's the fix? well, revert back to using CSS media queries! seriously stop using JavaScript to prevent rendering and instead just render everything, but just slap a --mobile modifier on the class name for the DOM element you want to render on mobile screens and update your CSS files to show/hide content or change other rules based on class names. it's a lot faster and more performant. it might mean you have to type more characters, but in the long run it will be worth it.


like this post? did i get anything wrong? discuss it on the forums at basementcommunity.com