react: Ignore
React 16.0.0 with SSR & lazysizes 4.0.1.
Trying to use the “the noscript pattern” to lazy load images with lazysizes but I’m seeing this:
Warning: Expected server HTML to contain a matching <img> in <noscript>.
Image component render method:
render () {
const { cdn, url, width, height } = this.props
if (!url) return null
const noScriptImgProps = {
src: `${cdn}${url}`,
className: classNames('product-image'),
width,
height
}
const imgProps = {
'data-src': `${cdn}${url}`,
className: classNames('product-image', 'lazyload'),
width,
height
}
return (
<span>
<noscript>
<img {...noScriptImgProps} />
</noscript>
<img {...imgProps} />
</span>
)
}
Does React have an issue with noscript tags…?
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 2
- Comments: 44 (10 by maintainers)
Commits related to this issue
- Ignore noscript content on the client (#11423) — committed to Ephem/react-lightyear by Ephem 6 years ago
- Ignore noscript content on the client (#13537) * Ignore noscript content on the client (#11423) * Fix failing test for ignoring noscript content * Add a ServerIntegration test for noscript — committed to facebook/react by Ephem 6 years ago
- Ignore noscript content on the client (#13537) * Ignore noscript content on the client (#11423) * Fix failing test for ignoring noscript content * Add a ServerIntegration test for noscript — committed to jetoneza/react by Ephem 6 years ago
OK, I understand why this happens now. But it’s not clear to me what’s the best fix.
As a workaround you can replace this:
with this:
I verified it works and doesn’t warn.
The reason you see the mismatch is because the browser is parsing the
noscriptcontent as text, but React attempts to hydrate it as a real tree. Maybe React shouldn’t attempt to hydrate anything innoscript.I tried with an
iframe, the below approach doesn’t work.It’s still coming as a string. For
image,petc have no problem. (Please forget the mismatch between src and all. Not working in both scenarios). And I found some other issues too if I used string literals.<iframe src="https://www.googletagmanager.com/ns.html?id=${val}></iframe>Hey @muhammadInam! Since I am unsure if the direction of the fix I suggested is good I’m waiting for feedback before doing a PR, maybe @gaearon who’s been active in the thread could chip in? (Only my last post is relevant in regards to a fix, rest is just background and context around how we use noscript and a bit wall-of-texty, sorry…)
Basically I think my questions are:
shouldSetTextContenttoo “late” a place to solve this optimally since the reconciler already knows about the children, props etc?<noscript>only contains text is kind of true on the client and solves the problem, but does it have any bad consequences/side-effects?If this is an obviously bad direction I’d be happy to let it go and let you work on it @muhammadInam, if it’s not terrible at first glance I’d be happy to open a PR and continue discussions there. 😃
This or next week. But I’ve said this a few times in the past…
After update to react 16.5.0 the warning is gone and
<noscript>content rendered even the child is not string. Thanks for the fix guys.This is a bug in 16.0.0: https://github.com/facebook/react/issues/11103. It was fixed in master via https://github.com/facebook/react/pull/11119 and will be released in the next update.
By adding a case to the SSR fixture I verified today that:
still works in master, but that:
is still broken in the way described, that is, it unnecessarily downloads the image.
I also verified that the solution I proposed in the comment above (adding
type === 'noscript'toshouldSetTextContent) does indeed make the second case work as expected.I would still be happy to send a PR for this, including the updated fixture. I might just go ahead and do that this weekend to have a better place to discuss the proposed solution. 😃
I am also using the noscript tag in a project in a similar fashion as @stephen-last. I have a long page of images, most of which are lazy loaded. For the ones that are lazy loaded, there is a coresponding noscript tag containing an image tag with the target source, this is the Google recommended way to provide SEO content for lazy loaded images. When React Hydration occurs, it looks like the img tag within the noscript tag gets ‘executed’, and the image is getting downloaded in the browser. If I look at the network tab in Chrome, I can see all of the noscript wrapped images have been requested. If I block React Hydration, and only rely on the SSR HTML, the noscript wrapped images do not get downloaded. React components that contain noscript tags should not attach the child contents as actual DOM nodes.
Sounds good. I haven’t looked into this again yet. A proof of concept would help the conversation.
Sounds good, @clemmy good luck with the studies!
@gaearon I will be prioritizing studies for the next few months. Please feel free to assign the task to someone else. 😄
@sebmarkbage When I use
<noscript>{staticMarkup}</noscript>I get:Using
<noscript dangerouslySetInnerHTML={{ __html: staticMarkup }} />produces no warnings with16.1.0-beta.On the general
<noscript>issue, after thinking about it over the weekend, I agree with @sebmarkbage. On the server React should allow any valid HTML or text. On the client React should ignore the contents completely, as that content only exists for when React doesn’t - in that way React has nothing to do with contents of<noscript>.I can’t think of a use case for React, or any script, to use the content of
<noscript>tags on the client.I guess in browsers where scripts are disabled this wouldn’t be parsed as text content. So it’s legit to put elements in there.
The issue is what happens on the client. Maybe client rendering should just ignore the content completely (and ignore hydration errors)?
I don’t quite fully understand the use cases where the content is used during a script enabled render. Are there such use cases?