ReactDOM renderToString adds empty HTML comments
Closed this issue ยท 5 comments
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
ReactDOM.renderToString adds an empty HTML comment.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:
const someVar = 'foo';
const htmlWithVariableAndCharacters = document.createTextNode(
ReactDOMServer.renderToString(
<div>{someVar}anyCharacters</div>
)
);
document.body.appendChild(htmlWithVariableAndCharacters);
HTML Output:
<div data-reactroot="">foo<!-- -->anyCharacters</div>
See it live here: https://codepen.io/anon/pen/mvORKd?editors=0010
What is the expected behavior?
Expected HTML output:
<div data-reactroot="">fooanyCharacters</div>
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Seen in React 16.7.0, do not know behavior in previous versions.
Something to keep in mind is if you open Chrome Development Tools you will not be able to see these HTML comments as Chrome strips them from being viewed in the developer pane. They can be seen in a server side render string output or if you right-click and choose 'Copy Element' and paste into a text editor.
This is by design and helps React hydrate those text nodes correctly.
@gaearon Oh, very interesting.
Note for folks that somehow land here, if you want to avoid the extra characters, particularly in long lists of things which can add up to thousands of characters can switch from something like:
Before
const someVar = 'foo';
const htmlWithVariableAndCharacters = document.createTextNode(
ReactDOMServer.renderToString(
<div>{someVar}anyCharacters</div>
)
);
document.body.appendChild(htmlWithVariableAndCharacters);
// Output: <div data-reactroot="">foo<!-- -->anyCharacters</div>
After
const htmlWithVariableAndNoCharacters = document.createTextNode(
ReactDOMServer.renderToString(
<div>{`${someVar}anyCharacters`}</div>
)
);
document.body.appendChild(htmlWithVariableAndNoCharacters);
// Output: <div data-reactroot="">fooanyCharacters</div>
Suspicion is this could be a candidate for Node.normalize()
? If that was called before render to compact the text nodes, would it then still be necessary to use the HTML comment trick to end up with the same output? Thinking out loud here.. https://developer.mozilla.org/en-US/docs/Web/API/Node/normalize
Had this showing up in two places in a list of 100 things:
<!-- -->
= 8 characters * 2 spots * 100 list items = 1600 extra characters
Gzip does eat this up though for sure, just seemed a bit odd. @gaearon thanks for the clarity!
@buildbreakdo woah thx mate! Took me ages to find someone with the same problem. I use react as content building tool where the render output is imported into a more or less standardized software solution and those comments killed the upload.
For future reference:
I came here with the same problem, since I was using renderToString
.
In my case, I don't need interactivity, so I ended up changing it to renderToStaticMarkup
.
You can see the differences here.
This is by design and helps React hydrate those text nodes correctly.
It may be by design. It may help hydrate more efficiently. But it's still a bug. HTML doesn't allow for comments in <title>
.
react-dom doesn't use comments to set a textarea
's value
. This is invalid:
<textarea name="example">
Some static text: {someDynamicValue}
</textarea>
React tells the developer to use defaultValue
(for uncontrolled) or value
(for controlled) textareas. Notably, it breaks if the user tries to use dynamic content inside a <textarea>
. The feedback is immediate and the message is clear. It's also consistent with other similar elements like <input defaultValue={โฆ} />
.
Conversely, the message for <title>
is unclear and is only a warning. Nothing is strongly pushing developers to apply the "correct" workaround for this bug. Nothing else in React prepares the engineer for the idea that <h1>{prefix} | {suffix}</h1>
is valid react, but <title>{prefix} | {suffix}</title>
is not. It's react internals leaking into user-space.
The docs for title say
children: <title> accepts only text as a child. This text will become the title of the document. You can also pass your own components as long as they only render text.
Assuming folks read the docs for such a small, seemingly-obvious element, that should probably read
children: <title> accepts only a single text node as a child. This text will become the title of the document. You can also pass your own component as long as it only renders text.