Skip to content
This repository has been archived by the owner on Oct 19, 2018. It is now read-only.

client component doesnt match rendered component explanation #94

Open
catmando opened this issue Nov 1, 2017 · 0 comments
Open

client component doesnt match rendered component explanation #94

catmando opened this issue Nov 1, 2017 · 0 comments

Comments

@catmando
Copy link
Contributor

catmando commented Nov 1, 2017

Users get this message:

Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
and wonder what it is

The message comes right out of react, so you would think you could find a nice SO explanation but I didn't.

So here goes.

First a little background on server-side rendering (or prerendering.) Server-side rendering works by running your hyperloop components in a javascript engine on the server, and saving the resulting HTML output. This is then shipped down to the client as the initial page view. So server-side rendering makes your hyperloop code work just like any other view templating engine.

Once the page is loaded on the client, react then renders your components again. If the checksum of the stuff it just rendered matches the checksum of the server rendered code then it can simply attach event handlers without updating the DOM.

If the checksums don't match then it has to update the DOM, and it gives you a warning to let you know that something might be wrong.

How does this happen? Consider the following component:

class TheTime < Hyperloop::Component
  render(DIV) do
    "The time is #{Time.now}"
  end
end

In this case the time will very likely be different between the server and client and so you will get the above warning.

These situations can almost always be fixed by moving some initialization to after_mount. This is because after_mount only runs on the client, never during pre-rerendering.

class TheTime < Hyperloop::Component
  after_mount do 
    mutate.time Time.now
  end
  render(DIV) do
    "The time is #{state.time}" 
  end
end

This will fix the problem because during both pre-rerendering and client rendering state.time will be nil and the generated html will be <SPAN>The time is </SPAN>. Then after client rendering is complete after_mount will run, the time state will be mutated causing a re-rerender.

It might appear that we have not accomplished anything because end up rendering TheTime component 3 times, and updating the DOM. However if TheTime is just one component buried in a larger app then we have accomplished a lot, because only TheTime has to be re-rerendered and not the whole component tree.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant