<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong></p>
<p dir="auto">Feature</p>
<p dir="auto"><strong>What is the current behavior?</strong></p>
<p dir="auto">Hydrating some server-rendered content can be difficult, inefficient or impossible. For example, in the process of rendering on the server, significant work or additional data may be required for data processing and conversion, such as custom templating or localization. The content can be large too, such as product information or a news article.</p>
<p dir="auto">When the resulting content is highly dynamic and changes with state, there is no choice but recreate it within React paradigm and recreate it on client. However, complicated server-generated content is often (if not typically) static. Delivering a redundant copy of static content to client just to compare and ignore it during hydration seems a waste of resources and can be prohibitively expensive.</p>
<p dir="auto"><strong>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 (<a href="https://jsfiddle.net/Luktwrdm/" rel="nofollow">https://jsfiddle.net/Luktwrdm/</a>) or CodeSandbox (<a href="https://codesandbox.io/s/new" rel="nofollow">https://codesandbox.io/s/new</a>) example below:</strong></p>
<p dir="auto"><a href="https://codesandbox.io/s/zx38ow3z8x" rel="nofollow">https://codesandbox.io/s/zx38ow3z8x</a></p>
<p dir="auto"><strong>What is the expected behavior?</strong></p>
<p dir="auto">Instead of additional complications of recreating it on the client with hydration, wouldn’t it be much easier to just accept the content from server as-is and tell hydrate() to leave it alone?</p>
<p dir="auto">There may be a few options for non-hydrating SSR:</p>
<ol dir="auto">
<li>Add a new callback <code class="notranslate">shouldComponentHydrate()</code> to disable hydration of component content</li>
</ol>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="export default class NoHydrate extends Component {
    // return false to avoid re-rendering of this component in hydrate()
    shouldComponentHydrate() {
        return false;
    }
    render() {
        // on server, simply render content
        // on client, this is never called and server content is accepted as-is
        return (
            &lt;div&gt;
                {this.props.children}
            &lt;/div&gt;
        );
    }
}
"><pre class="notranslate"><span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-k">class</span> <span class="pl-v">NoHydrate</span> <span class="pl-k">extends</span> <span class="pl-v">Component</span> <span class="pl-kos">{</span>
    <span class="pl-c">// return false to avoid re-rendering of this component in hydrate()</span>
    <span class="pl-en">shouldComponentHydrate</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span> <span class="pl-c1">false</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
    <span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-c">// on server, simply render content</span>
        <span class="pl-c">// on client, this is never called and server content is accepted as-is</span>
        <span class="pl-k">return</span> <span class="pl-kos">(</span>
            <span class="pl-c1">&lt;</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
                <span class="pl-kos">{</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">.</span><span class="pl-c1">children</span><span class="pl-kos">}</span>
            <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
        <span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<ol start="2" dir="auto">
<li>Access SSR content from DOM in <code class="notranslate">render()</code><br>
<em>This is probably the worst option, though it is the only one that definitely works currently.</em></li>
</ol>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="export default class AutoHydrate extends Component {
    render() {
        // on server, simply render content
        // on client, find SSR in dom and re-render using dangerouslySetInnerHTML
        // ** requires a unique id, generated before or during server rendering **
        return (typeof window === 'undefined') ? (
            &lt;div id={this.props.id}&gt;
                {this.props.children}
            &lt;/div
        ) : (
            &lt;div id={this.props.id}
                dangerouslySetInnerHTML={{
                    __html: document.getElementById(this.props.id).innerHTML
                }}
            /&gt;
        );
    }
}"><pre class="notranslate"><span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-k">class</span> <span class="pl-v">AutoHydrate</span> <span class="pl-k">extends</span> <span class="pl-v">Component</span> <span class="pl-kos">{</span>
    <span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-c">// on server, simply render content</span>
        <span class="pl-c">// on client, find SSR in dom and re-render using dangerouslySetInnerHTML</span>
        <span class="pl-c">// ** requires a unique id, generated before or during server rendering **</span>
        <span class="pl-k">return</span> <span class="pl-kos">(</span><span class="pl-k">typeof</span> <span class="pl-smi">window</span> <span class="pl-c1">===</span> <span class="pl-s">'undefined'</span><span class="pl-kos">)</span> ? <span class="pl-kos">(</span>
            <span class="pl-c1">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">id</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">.</span><span class="pl-c1">id</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span>
                <span class="pl-kos">{</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">.</span><span class="pl-c1">children</span><span class="pl-kos">}</span>
            <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1"></span>
        <span class="pl-kos">)</span> : <span class="pl-kos">(</span>
            <span class="pl-c1">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">id</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">.</span><span class="pl-c1">id</span><span class="pl-kos">}</span>
                <span class="pl-c1">dangerouslySetInnerHTML</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-kos">{</span>
                    <span class="pl-c1">__html</span>: <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">getElementById</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">.</span><span class="pl-c1">id</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-c1">innerHTML</span>
                <span class="pl-kos">}</span><span class="pl-kos">}</span>
            <span class="pl-c1">/</span><span class="pl-c1">&gt;</span>
        <span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<ol start="3" dir="auto">
<li>Use <code class="notranslate">dangerouslySetInnerHTML</code> with empty content<br>
<em>It actually works now, but it is not documented that it is supposed to.</em></li>
</ol>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="export default class Ssr extends Component {
    render() {
        // on server, simply render content
        // on client, render empty content using dangerouslySetInnerHTML,
        // which normally causes a warning of content mismatch and keeps the existing content
        // also add suppressHydrationWarning to turn off the warning.
        return (typeof window === 'undefined') ? (
            &lt;div&gt;
                {this.props.children}
            &lt;/div&gt;
        ) : (
            &lt;div
                dangerouslySetInnerHTML={{
                    __html: ''
                }}
                suppressHydrationWarning
            /&gt;
        );
    }
}"><pre class="notranslate"><span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-k">class</span> <span class="pl-v">Ssr</span> <span class="pl-k">extends</span> <span class="pl-v">Component</span> <span class="pl-kos">{</span>
    <span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-c">// on server, simply render content</span>
        <span class="pl-c">// on client, render empty content using dangerouslySetInnerHTML,</span>
        <span class="pl-c">// which normally causes a warning of content mismatch and keeps the existing content</span>
        <span class="pl-c">// also add suppressHydrationWarning to turn off the warning.</span>
        <span class="pl-k">return</span> <span class="pl-kos">(</span><span class="pl-k">typeof</span> <span class="pl-smi">window</span> <span class="pl-c1">===</span> <span class="pl-s">'undefined'</span><span class="pl-kos">)</span> ? <span class="pl-kos">(</span>
            <span class="pl-c1">&lt;</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
                <span class="pl-kos">{</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">.</span><span class="pl-c1">children</span><span class="pl-kos">}</span>
            <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
        <span class="pl-kos">)</span> : <span class="pl-kos">(</span>
            <span class="pl-c1">&lt;</span><span class="pl-ent">div</span>
                <span class="pl-c1">dangerouslySetInnerHTML</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-kos">{</span>
                    <span class="pl-c1">__html</span>: <span class="pl-s">''</span>
                <span class="pl-kos">}</span><span class="pl-kos">}</span>
                <span class="pl-c1">suppressHydrationWarning</span>
            <span class="pl-c1">/</span><span class="pl-c1">&gt;</span>
        <span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Considering that there is a way to make it work now, documenting (3) may be all that needs to happen. However if (1) could be added with same behavior, it would look cleaner.</p>
<p dir="auto"><strong>Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?</strong></p>
<p dir="auto">Version 16.2. Not sure if the working option 3 has worked before or is supposed to work in future versions.</p>
<p dir="auto">The New York Times is <a href="https://open.nytimes.com/react-relay-and-graphql-under-the-hood-of-the-times-website-redesign-22fb62ea9764" rel="nofollow">rebuilding its website</a> using React. Currently, it’s an isomorphic app that has both server- and client-side renders.</p>
<p dir="auto"><strong>Our question: What's the best way to include a non-React interactive graphic — maps, charts and other visualizations created by custom code — within a fully React page?</strong></p>
<p dir="auto">Our ideal scenario:</p>
<ul dir="auto">
<li>Server-side React renders the initial HTML for a graphic, using <code class="notranslate">dangerouslySetInnerHTML</code>, as part of a React page</li>
<li>Client-side React never touches those elements again, even during component mounting</li>
</ul>
<p dir="auto">We thought React 16 might solve this with <code class="notranslate">hydrate</code> method, but it still removes nodes that it doesn't expect, such as nodes generated by D3 or other client-side code. None of the options in <a href="https://facebook.github.io/react/docs/integrating-with-other-libraries.html" rel="nofollow">Integrating with Other Libraries</a> seem to be an exact match either.</p>
<p dir="auto">The classic use case is a graphic with a D3 map. The server-side HTML includes text and a placeholder </p><div dir="auto"> for the map, as well as the map JS. On page load, the map is immediately drawn by D3 but gets erased when React mounts client-side. The D3 nodes aren’t included in the server-side output, because they often vary based on viewport, device, etc.<p dir="auto"></p>
<p dir="auto">Here’s a <a href="https://jsfiddle.net/6zdhrych/" rel="nofollow">trivial example</a>, showing React 16’s <code class="notranslate">hydrate</code> removing client-created nodes after one second. On mobile devices, loading the React library and potentially other dependencies could take some seconds.</p>
<p dir="auto">The simplest solution I can think of is a <code class="notranslate">shouldComponentMount</code> function, where we could return false. The rest of the React components on the page would mount, but leave the interactive graphic part alone. There are probably other solutions.</p>
<p dir="auto">Constraints:</p>
<ul dir="auto">
<li>We need to use dangerouslySetInnerHTML, because we need to deploy graphics outside of site releases</li>
<li>We need to render the initial HTML server-side for performance and simplicity</li>
<li>We can’t use iFrames for everything, as they’re not flexible enough</li>
<li>We can’t re-render or reattach elements, as that causes many problems — CSS animations restart, media playback is interrupted, input cursors and text selections are lost, etc.</li>
</ul>
<p dir="auto">Any guidance is appreciated.</p>
<p dir="auto">cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/gaearon/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/gaearon">@gaearon</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/leeb/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/leeb">@leeb</a></p></div>