Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Components that render non-empty <noscript>s can't re-render #7607

Closed
wchargin opened this issue Aug 29, 2016 · 4 comments
Closed

Components that render non-empty <noscript>s can't re-render #7607

wchargin opened this issue Aug 29, 2016 · 4 comments

Comments

@wchargin
Copy link

Do you want to request a feature or report a bug?
Bug (from a React user's perspective).

Why does this matter?
This matters in the context of server-side rendering. I want to have the structure

render() {
    return <div>
        <noscript><StaticComponent /></noscript>
        <DynamicComponent className="yesscript" />
    </div>;
}

where my page template contains <noscript><style>.yesscript{display:none;}</style></noscript>. Then JS-disabled users will see the static one, JS-enabled users will see the dynamic one, and everyone will be happy.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template: https://jsfiddle.net/reactjs/69z2wepo/).
https://jsfiddle.net/r1k4q6tx/; open the JS console, then click the "Re-render" button in the fiddle

What is the current behavior?
Uncaught Invariant Violation: Unable to find element with ID 3.

What is the expected behavior?
The button should update to "Re-render (1)", as it does when you remove set includeNoscript = false.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
I tried 15.3.1 in Chrome 52 Linux. (I understand why it's happening, so I don't think the browser or OS is an issue. The JSX for the fiddle seems not to work in Firefox, but I can reproduce the non-minimal version of the problem there, too.)

I don't know much about how the rehydration process works, but it seems like a reasonable solution might be to pass right over noscripts when rehydrating; if JS is enabled, they won't be visible anyway. (In Chrome and Firefox, at least, the noscript setting seems to be constant mod a refresh, so we don't have to worry about changing between renders.)

It seems to me like this might deserve a fix in trunk, but I would also appreciate any workaround (short of rendering a <noscript><App /></noscript> and outputting the whole page twice, which I would really prefer not to do).

@wchargin
Copy link
Author

Or, to amend my penultimate paragraph: perhaps a more reasonable solution would be to just patch the dehydration process instead—if

<noscript data-reactid="2"><span data-reactid="3">hello</span></noscript>

becomes instead

<noscript data-reactid="2"><span>hello</span></noscript>

then I don't imagine that React would have any problems. Essentially, use renderToStaticMarkup instead of renderToString when inside a noscript. The same reasoning applies (any updates thither won't matter anyway).

@wchargin
Copy link
Author

Okay; looks like it's not quite as easy as I'd thought. I implemented it (really hackily because I haven't looked at the React code before), and it passes all tests and does the right thing on the server: i.e., it outputs <noscript data-reactid="2"><span>hello</span></noscript><span data-reactid="3">after</span>. But at rehydration time React tries to precacheChildNodes of the noscript and chokes because it doesn't contain any child nodes. My immediate attempts to patch that were unsuccessful.

Still open to suggestions! :-)

@syranide
Copy link
Contributor

Related #1252

@wchargin
Copy link
Author

Thank you—not sure how I missed that in my search. I'll take discussion there.

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

No branches or pull requests

3 participants