What is Server Rendering?
Server rendering is generating the initial HTML on the server so users see some content immediately when the page loads. This can be done in two ways:
Server-Side Rendering (SSR): Generates HTML on the server each time a page is requested.
Static Site Generation (SSG): Pre-generates HTML at build time or uses cached versions from previous requests.
Why is Server Rendering Useful?
With client rendering, the process looks like this:
- Load markup without content.
- Load JavaScript.
- Fetch data with queries.
This requires at least three server roundtrips before the user sees any content.
Server rendering simplifies this process:
- Load markup with content and initial data.
- Load JavaScript.
The user sees content as soon as step 1 is complete, and the page becomes interactive after step 2. The initial data is already included in the markup, so there's no need for an extra data fetch initially!
An Important Detail
When using React Query with server rendering, there are actually three queryClient instances involved in the process:
- Preloading Phase:
Before rendering, a queryClient is created to prefetch data.
Necessary data is fetched and stored in this queryClient. - Server Rendering Phase:
Once data is prefetched, it's dehydrated (serialized) and sent to the server rendering process.
A new queryClient is created on the server and injected with dehydrated data.
This ensures the server generates fully populated HTML for the client. - Client Rendering Phase:
Dehydrated data is passed to the client.
Another queryClient is created on the client and rehydrated with the data.
This ensures the client starts with the same data, maintaining consistency and skipping initial data fetching.
This ensures all processes start with the same data, so they can return the same markup.
High memory consumption on the server
When you create a QueryClient for each request in React Query, it generates an isolated cache specific to that client. This cache remains in memory for a specified period known as the gcTime. If there's a high volume of requests within that period, it can lead to significant memory consumption on the server.
By default, on the server, gcTime is set to Infinity, meaning manual garbage collection is disabled, and memory is automatically cleared once a request is completed. However, if you set a non-Infinity gcTime, you're responsible for clearing the cache early to prevent excessive memory usage.
Avoid setting gcTime to 0, as it might cause a hydration error. The Hydration Boundary places necessary data into the cache for rendering. If the garbage collector removes this data before rendering completes, it can cause issues. Instead, consider setting it to 2 * 1000, allowing sufficient time for the app to reference the data.
To manage memory consumption and clear the cache when it's no longer needed, you can call queryClient.clear() after handling the request and sending the dehydrated state to the client. Alternatively, you can opt for a smaller gcTime to automatically clear memory sooner. This ensures efficient memory usage and prevents memory-related issues on the server.
In wrapping up, React Query simplifies the process of fetching and caching data, especially when dealing with server-side rendering. By fetching data in advance on the server and seamlessly transferring it to the client, React Query ensures a smooth and consistent user experience. Plus, with features like adjusting the memory management settings, developers can fine-tune performance to meet their application's needs. With React Query, developers can focus on building engaging applications without worrying about complex data management tasks, ultimately delivering faster and more responsive user experiences.