tobik
tobik

Reputation: 7198

Different markup generated on server and client from the same JSX code

This is my JSX:

<h4>{post.title} <small> (by {post.author})</small> </h4>

This is what is generated on the server (using React.renderComponentToString()) and sent to the client.

<h4 data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0">
    <span data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0.0">Why JavaScript is eating the world.</span>
    <span data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0.1"> </span>
    <small data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0.2">
        <span data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0.2.0"> (by </span>
        <span data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0.2.1">spike</span>
        <span data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0.2.2">)</span>
    </small>
    <span data-reactid=".2ggx1vlvrwg.1.0.0.$posts-about.$2.0.3"></span>
</h4>

And this is what is generated on the client side (in browser):

<h4 data-reactid=".0.1.0.0.$posts-about.$2.0">
    <span data-reactid=".0.1.0.0.$posts-about.$2.0.0">Why JavaScript is eating the world.</span>
    <small data-reactid=".0.1.0.0.$posts-about.$2.0.1">
        <span data-reactid=".0.1.0.0.$posts-about.$2.0.1.0"> (by </span>
        <span data-reactid=".0.1.0.0.$posts-about.$2.0.1.1">spike</span>
        <span data-reactid=".0.1.0.0.$posts-about.$2.0.1.2">)</span>
    </small>
</h4>

Apparently two spans are missing and that's causing React attempted to use reuse markup in a container but the checksum was invalid. error.

I suppose that the problem is in the JSX compiler. The generated JavaScript that is bundled and sent to the client is different from what the server is using.

Funny thing is that if I "fix" the indentation in JSX, it works. Both server and client generate the same HTML markup without those extra spans.

<h4>{post.title}
    <small> (by {post.author})</small>
</h4>

However I haven't read anything in the documentation about being careful width JSX indentation and this makes me a little bit nervous because this kind of problem is hard (or at least annoying) to debug.

Upvotes: 0

Views: 383

Answers (2)

tobik
tobik

Reputation: 7198

The problem was caused by an out-dated version of reactify. As a consequence two different versions of JSX compiler were used. As @FakeRainBrigand pointed out, the rules for treating whitespaces in JSX have changed recently and that caused the difference in compiled JavaScript.

Upvotes: 3

Brigand
Brigand

Reputation: 86250

JSX handling of whitespace makes a lot of sense when you understand the rules.

  • If it's on the same line it will work exactly like html whitespace
  • Spaces directly before or after a new line character are removed

The last rule is different from HTML for a very good reason. If you have a list of things, and you don't want a space between them in HTML, you have to pick one of these:

 <ul><li>Apples</li><li>Oranges</li></ul>
<ul><!-- 
  --><li>Apples</li><!--
  --><li>Oranges</li><!--
--></ul>

As wonderful as those are, in JSX it can either look like the first one, or

<ul>
  <li>Apples</li>
  <li>Oranges</li>
</ul>

And if you do want the space you can either insert it inside one of the elements

<ul>
  <li>Apples </li>
  <li>Oranges </li>
</ul>

or put a very explicit literal space where you want it

<ul>
  <li>Apples</li>
  {' '}
  <li>Oranges</li>
</ul>

It has the side bonus of being my new favorite emoticon {' '}

Upvotes: 1

Related Questions