How to catch React Hydration errors on production
Since many were demanding a demo for this, I have added a demo on GitHub and hosted it on Vercel.
In our organization, we have encountered multiple occasions when the server-side rendered HTML and client-side rendered HTML don't match and this results in React hydration errors.
If you are not familiar with server-side rendering, you can read it here and if you are not familiar with React Hydration, then check out this article.
We always ensure that the server-side and client-side HTML matches but still, hydration error occurs due to a small bug getting merged even after multiple code reviews. Once it gets released, then we are not aware for a long time that if any hydration error is occurring on some pages because React doesn't throw any hydration error on the production build of React.
Consequences of React Hydration errors
If React hydration errors exist in production, then there can be direct and indirect issues. Following are some of the issues that occurred on our production builds:
- First and foremost, the application is not working as intended. The user might see something different from what is expected.
- Since we do server-side rendering for SEO benefits, there are some cases when the user sees the desired HTML but web crawlers get broken HTML or even some cases empty HTML due to hydration error.
- When a large hydration error occurs, like the text content of div is not rendered, it contributes significantly to the CLS score.
- Even if a single hydration error exists on the production build of React, you cannot log it so as to track it and fix it immediately.
How we managed to reduce these React hydration errors on production?
Since we now know that React doesn't throw any hydration errors in the production build of React, so does it provide any kind of API to hook into to know if hydration has occurred?
The answer is NO. This is because to detect any hydration error, it needs to match the HTML smartly and need to track the attributes. This would decrease the performance of React in the production that we enjoy.
So going forward until React provides any API, we need to do something at our end. So we decided that at least we can try to reduce these errors and somehow try to catch them early and notify the developer during the development phase by logging it.
We did this by monkey patching the console.error() function. I know this is not the most elegant solution but here not much is left by the React itself.
If you have a better solution for this problem or have a suggestion, then feel free to comment or just drop a mail to me.
Here we expose the function patchConsoleError()
. Call this function from your app such that this is invoked only once and call as early as possible so that we don't lose any errors before patching it. Also, make sure to call this function only in developement
mode.
Following are the steps that we perform while monkey patching:
- Save the reference to the original
console.error()
function since we will later updateconsole.error
with our own function. - Check if the current error is a React hydration error. We check it by maintaining an array of the common hydration errors that React throws. We need to update this array
(HYDRATION_ERROR_MSGS)
at our end, if React changes/adds a new error message in the future but it hasn’t happened yet. - If it is a React hydration error then we process it to readable form. We do this by interpolating the error message template with the params. This returns the same message as it is shown in the browser DevTools console. Instead of using
interpolate()
, one can alternatively use the sprintf-js npm package also. - After processing the hydration error, we report it to our servers by calling an API to log it in our logging channel which would notify the developer instantly during the development itself.
- Finally, update the newly created
error()
function toconsole.error
.
NOTE: In some scenarios, if you get the HTML dynamically and render it using the dangerouslySetInnerHTML prop, then this won’t work as these errors won’t be generated on development and cant be catched on production .
Conclusion
If you are looking to reduce the React hydration errors on production, then one of the ways is to reduce the hydration errors during the development phase itself by monkey patching the console.error() function and then logging the hydration error.
You can read more about the discussion on React hydration errors on production in this Github Issue.
For any further queries, comment down below or reach out to me on my mail: amitsingh5198@gmail.com