question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

After client side render following SSR, the rendered html is out of sync with the react tree.

See original GitHub issue

Bug report

Describe the bug

We request the page, and initially it looks fine. It appears server side hydration is working as expected. But a second or so later, after React initialises on the client, some html ends up rendered in the wrong place (sometimes randomly inside sibling elements).

The page source html is correct, so it must be rendering okay on the server. The react tree itself, and where it says the html is, is in line with what we would expect. However the html itself is wrong, and out of sync with the react tree shown in the dev tools. Forcing a re-render in the dev tools appears to fix it.

eg

React tree and page source show:

<div class="a"></div> 
<div class="b"></div> 
<div class="c"></div> 

but actual rendered html is something like:

<div class="a">
  <div class="b"></div> 
</div> 
<div class="c"></div> 

To Reproduce

  1. Go to https://lounge.gamerjibe.com/lounge/MoxieBoosted/members
  2. Create an account and log in (sorry i know that’s annoying… it only replicates when you’re logged in. I promise this isnt some scam to get sign ups haha. It’s a simple one click if you have discord anyway)
  3. See the cards initially look fine.
  4. After some time (it appears to be exactly when commons.js is fully received… Add some network throttling to see the issue clearer) the cards re-render and the html is broken on some of them.
  5. Check the React tree and inspect the broken card. Notice the html does not match the react tree.
  6. Client side navigate to the ‘Home’ tab or anywhere else in the app, and end up back on that members page, and notice that the error does not occur when the page is loaded purely client side.

Expected behavior

The rendered html should match the react tree in the dev tools exactly.

System information

Appears to replicate across all machines and browsers.

Additional context

We’ve also seen this issue in other places in the app, this is just the most obvious one. A pattern we’ve noticed is that it only happens in elements rendered via an array map (ie the cards).

We’ve done all we can to optimise these lists (memoized selectors, unique element keys etc etc) and I really dont think what we’re trying to do should be too much work for react.

It appears to happen when commons.js is loaded. Im not 100% what comes in that file, but i imagine it’s the core react scripts that then initialise and create the virtual DOM, which is why the page rerenders after it loads?

We’re using styled-components, but this issue was present before switching to styled components from sass. You’ll be able to see our redux actions in redux devtools.

I saw on another issue something similar was happening due to invalid html. I’ve run this (https://validator.w3.org/nu/?showsource=yes&doc=https%3A%2F%2Flounge.gamerjibe.com%2Flounge%2FMoxieBoosted%2Fmembers) and fixed the errors locally, but it doesn’t fix the issue.

Any help here would be hugely appreciated. I can’t seem to find anyone else having the same issue.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:16
  • Comments:29 (8 by maintainers)

github_iconTop GitHub Comments

14reactions
designbyadriancommented, Jun 20, 2019

Please don’t close this issue, as we’re still not sure where the issue lies. It took me hours to find this discussion!

Has anyone got an update on this?

10reactions
kaluabentescommented, Jul 17, 2020

Basically, what you need to do is do whatever transformations that depend on any browser API just after the component has mounted:

import React from "react";

export default function useHasMounted() {
  const [hasMounted, setHasMounted] = React.useState(false);

  React.useEffect(() => {
    setHasMounted(true);
  }, []);

  return hasMounted;
}
import { useEffect, useState } from "react";
import useHasMounted from "./useHasMounted";

export default function useResponsive() {
  const intialValue = process.browser ? window.innerWidth < 769 : false;
  const [isMobile, setIsMobile] = useState(intialValue);
  const hasMounted = useHasMounted();

  useEffect(() => {
    const handleResize = () => {
      if (window.innerWidth > 768) {
        setIsMobile(false);
        return;
      }

      setIsMobile(true);
    };

    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return isMobile && hasMounted;
}

When React do the rehydration phase, if the output rendered in the server side is different from the generated in the rehydration phase this makes React be confused and makes him render the output in a wrong way, so what you need to do is assure that the output generated by the server be exactly the same to the generated by the rehydration phase (that have access to browser apis, this is the reason why the output differs) and wait for the component to mount, that happens after the rehydration phase to make any changes based in-browser API or any other type of client-side data

Read more comments on GitHub >

github_iconTop Results From Across the Web

react-hydration-error - Next.js
The first render is called Hydration which is a feature of React. This can cause the React tree to be out of sync...
Read more >
Server-side rendering - Apollo GraphQL Docs
Server-side rendering (SSR) is a performance optimization for modern web apps. It enables you to render your app's initial state to raw HTML...
Read more >
Virtual DOM and Internals - React
The virtual DOM (VDOM) is a programming concept where an ideal, or “virtual”, representation of a UI is kept in memory and synced...
Read more >
Server Rendering - Redux - JS.ORG
When the server receives the request, it renders the required component(s) into an HTML string, and then sends it as a response to...
Read more >
Server-Side Rendering (SSR) - Vue.js
What is SSR? #. Vue.js is a framework for building client-side applications. By default, Vue components produce and manipulate DOM in the browser...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found