For Ad performance in an isomorphic application we need React to avoid rendering an Ad Component containing an ad position div on the client initial load. Here is the following scenario:
If there is a way to conditionally stop React from rendering the ad position div on the client, we have not found it.
Seems like there needs to be a flag or method in the react lifecycle that can be used to prevent a component render on certain conditions.
@scsherwood Can't you just make the Google gpt request in componentDidMount, and then rerender with the results of this call. So react will finish 'rendering' the same markup as was sent from the server, and the ad request can happen separately after initial rendering is complete.
@jblok the reason why we cant make it in componentDidMount is because:
Yes, but so is your entire app so this shouldn't be a downside really.
Visually speaking, the app is present on first byte. The lifecycle on the client side ties up firing the gpt request.
I'm unclear - do you mean the script is a third party ad script which just runs on page load regardless?
The script is the bundled javascript (react, miscellaneous vendor scripts, app scripts, etc). GPT is loaded in the head of the document.
Let me know if you have any more questions to clarify.
Our goal is to visually render a full page with ads under ~2-3 seconds.
We are trying to get out in front of the React render to get faster
performance out of the ads. Waiting on react costs us around 500 to 1000
ms before the ad call is made.
_Steven *_Sherwood *
_w:_ 770-226-2527 _e:_ steven.[email protected]
http://weather.com/apps http://weather.com/apps
http://weather.com/apps http://weather.com/apps
http://weather.com/apps http://weather.com/apps
On Tue, Oct 25, 2016 at 11:18 AM, Jonathon Blok [email protected]
wrote:
@scsherwood https://github.com/scsherwood Can't you just make the
Google gpt request in componentDidMount, and then rerender with the results
of this call. So react will finish 'rendering' the same markup as was sent
from the server, and the ad request can happen separately after initial
rendering is complete.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react/issues/8017#issuecomment-256065424,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEasemDdfdnGKbHGiTdVUhF7jnoO8vWyks5q3h3CgaJpZM4Ka_m4
.
Another option may be to have an off-screen <div>
rendering the ad from the server-state at load time and push the rendered html into your store.
Then at the components componentDidMount
you simply grab the html from store and set it inside a <span>
in your target component using https://facebook.github.io/react/docs/dom-elements.html#dangerouslysetinnerhtml
This assumes you can determine when your ad service has finished rendering.
Use state for this:
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = { hasMounted: false };
}
componentDidMount() {
this.setState({ hasMounted: true });
}
render() {
return (
<div>
<p>This text is rendered on the server.</p>
{this.state.hasMounted && <p>This text only appears after mounting.</p>}
</div>
);
}
}
Generally we don't recommend setState()
in componentDidMount()
because it causes an extra re-rendering, but in your case this sounds exactly like what you need.
Ill prepare a sample repo to illustrate situation
Recently opened up a discussion with Kevin Lacker, and tried to reproduce our application on a smaller example repo, and was not able to reproduce the ads wipeout issue.
https://github.com/roastlechon/react-component-wipeout-example
My theory is that one of our libraries that we are using is causing a rerender, which causes the warning message for
React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server
I will continue to do some digging to determine what exactly is the library causing issues
@scsherwood have you found the solution? I have exactly same issue - DFP ad disappears when React client app has been loaded
@snegostup @roastlechon we have the same problem with GPT/AdSense ads.
If we wait to show the first add until React is loaded (around 2 seconds) it destroys the viewability of that first ad.
We need it to load the ad before React is loaded. That's really simple using SSR, but React wipes it out in the hydration phase.
We are surprised there isn't any solution or workaround for this yet, so any insight is really welcomed :)
@luisherranz we were able to diagnose and figure out that it was a hydration mismatch that occurred which wiped out the dom in hydration.
GPT is able to load beforehand with the server side rendered markup and on hydration nothing is wiped out (after we fixed the issue with mismatch).
@roastlechon thanks for your answer.
Our error is:
Warning: Did not expect server HTML to contain a <ins> in <ins>.
We only render one <ins>
in React. The other <ins>
tag inside it is rendered by the adsbygoogle.js
library before React is loaded.
So our mismatch is not really happening between our server and client code, but from our sever code, with the additional tags created by adsbygoogle
, and the client code after React finally loads.
@roastlechon wait can you elaborate? Hydration should blow everything away, no? If your ad renders after server side render but before client render, why would the client hydration honor the ad and keep it there?
@gaearon That makes sense but in this case, we want to suppress React client hydration totally as in our example, the html has updated between server & client render.
@reywright it will keep it there if React renders exactly the same thing on both sides. For example:
const { id } = this.props;
return (
<div
suppressHydrationWarning
dangerouslySetInnerHTML={{__html: `<div id="${id}"></div>`}}
/>
);
Browser renders the ad even before this code loads, client-render-phase happens but doesn't touch the previously-created DOM nodes since that React DIV has the same properties.
@eliseumds Thats fine, but the third party ads library might be adding multiple dom nodes, adding some dom attributes, etc. The Application has no way of knowing that beforehand, so its not possible to have the same markup rendered on the server side.
@scsherwood any luck ?
We facing the exact same issue, our ads library modifies the Dom just before React client side hydration. React 15 was fine with it, but React 16 goes and removes the Dom Nodes altogether. We don't want to wait till componentDidMount
to go and actually render the ads dom nodes, because its freaking slow. I think there should be some way to tell React: don't update this dom, I'll manage it myself.
There are lots of use cases in real world applications for this requirement.
Another vote for the don't update this dom, I'll manage it myself
option 👍
Note we generally don’t read discussions in closed issues. If this is still relevant please file a new issue with a more focused description of what you’re struggling with, and some demos.
@gaearon wouldn't it be better to reopen this one?
For anybody finding this thread and still having this problem, as of React 16.1.1 this very helpful comment on a related RFC seems to be exactly what you're looking for, similar to what @eliseumds was proposing.
<div
dangerouslySetInnerHTML={{ __html: '' }}
suppressHydrationWarning
/>
Note that the current behavior of
dangerouslySetInnerHTML
is to keep the current content when the content being set is different. In combination withsuppressHydrationWarning
it produces the desired behavior already.
Most helpful comment
Use state for this:
Generally we don't recommend
setState()
incomponentDidMount()
because it causes an extra re-rendering, but in your case this sounds exactly like what you need.