Per the source here https://github.com/nfl/react-helmet/blob/master/src/Helmet.js#L197 I can see that Helmet blows away managed tags and re-adds them. Why does it do this? It leads to problems like this one http://stackoverflow.com/questions/37355346/script-tag-runs-twice-in-universal-react-application-fb-plugin/37555818#37555818 which is a problem that also affects me.
I'd be happy to submit a pull to change this behaviour, but thought perhaps there was a good reason. Thanks!
@henrybaxter Thanks for bringing this to our attention. This is an issue that arises from the nature of react-side-effect because it re-renders every Helmet in the component tree because each one is unaware it is the last one in the tree. We are looking into fixing this by delaying the update of tags until the very last component so that it may update only once; then the checks we have put in place should prevent your script (or any other) tags from getting blown away unnecessarily.
As a workaround in the interim, if possible, put all your tags in the root and you'll see that tags coming from the server will not be removed and re-added.
I've been dealing with an issue with server rendering memory leak with my components being duplicated and not being removed from memory. Would this be related?
@athomann I don't think that issue is related. Helmet does not duplicate components, it takes strings of data and converts them to HTML metadata.
@doctyper It appears my issue has to do with react-side-effect and not calling .rewind
https://github.com/gaearon/react-document-title#server-usage
+1
in my case, main.css which is my main stylesheet reloads and causes FOUC(Flash Of Unstyled Content)
my homepage link
I use both server side react-helmet(rewind) and client side react-helmet (
Hello, just wondering if there's been any thought on this issue? Just because it will affect our tracking code
The workaround until this bug is fixed is to put the server side tags you care about in the root of your app. Unfortunately this does take away the power of nesting at this moment, but those tags in the root will not get blown away on the client side.
Having the same problem.
Had the same problem. I just ended up removing head.script.toString(). They won't be server rendered, but at least when client loads script tags are added to meta.
I have some isssue, script loads twice on ${head.script.toString()} method. Problem has solve with using head script tag with async in
on server instead at the end of html.Same here, first server renders head.script well. And then it renders the script again when all react js is fully loaded.
There is a big problem. I spend some hours for research reason why react-router and redux after browserHistory.push() loaded twice with Provider, Router components and why partically I have errors "two valid but unequal nodes with the same data-reactid". It's broke all app's logic.
Using ${head.script.toString()} in the head tag does not solve this bug, we need possible to prevent loading bundle scripts twicely.
So, there is a good approach to made environment checks like this:
<Helmet
link={[
{ rel: 'stylesheet', href:${STATIC_DOMAIN}/assets/css/bundle-property.css},
]}
script={[
{ src: !process.env.BROWSER ?${BUNDLES_DOMAIN}/bundle-for-server.js:${BUNDLES_DOMAIN}/bundle-for-browser.js, type: 'text/javascript', async: true },
]}
/>
That would be good to have a ability to set params that enables rendering data through server or browser side. It should decide proble.
My idea to fix this would be to have the first client-side render wait until all instances are mounted before it does it's client state change. To do that I'd need to hydrate the client with the number of instances to wait for. Any ideas on where and how the client should be hydrated?
I'm considering putting a data attribute on one/all the Helmet tags or just the html tag. Something like data-react-helmet-numMountedInstances. Open to better ways to hydrate the client, but definitely need to communicate the number of instances.
Of course, we could just skip the first client side render, that may be too loose as there may be a mismatch between server and client. At least allowing for one client change after the SSR, we can fairly compare, and in a best situation there should be no change.
Thanks for the input!
As of version 5, Helmet no longer re-creates tags if the server-rendered tags match their client-rendered equivalents. Relevant test: https://github.com/nfl/react-helmet/blob/master/test/HelmetDeclarativeTest.js#L3019-L3040
After facing the issue for long hours, note that rendering your scripts in the body causes a double rendering. I had to move them in the head section of my document, adding them a defer attribute to keep acceptable performances.
@doctyper I'm just getting up to speed with this, but I don't think the test you referenced is a valid test comparing the recommended SRR {head.link.toComponent()} output to the client side output because the mock SSR tag in the test doesn't have a data-reactid attribute.
I'm running [email protected], and the {head.link.toComponent()} call on the server returns the following markup:
<link data-react-helmet="true" rel="stylesheet" type="text/css" href="//0.0.0.0:8001/static/en-US/main.c1030da.css" data-reactid="5"/>
note the data-reactid="5" attribute.
I tried updating the test in test/HelmetDeclarativeTest.js, and it fails when the mock tag includes data-reactid.
This issue should probably be re-opened, or consolidated into https://github.com/nfl/react-helmet/issues/98
@mmcgahan I am also just now seeing this issue with the latest react-helmet.
isEqualNode seems to be the one causing me grief
After digging further, updateTags should not be called if my react elements are already server side rendered, but I need more information as to how it knows when to run updateTags
I moved my Helmet components higher up the tree and they seem to work as expected.
In my situation, I have an App component, i18n provider, redux provider, followed by a Layout component. Inside the layout component are divs which contain Helmet components.
There is also a routing piece that is used here which upon initial load (rehydrating from server), it seems to have trouble understanding that the elements were already there.
Also recently upgraded react-helmet to get rid of prop-types warning and then also came across with this issue. Tried both 5.0.0 and 5.1.3 and both have the same issue. Downgrading to 4.0.0 works again just fine.
Using a Helmet server-rendered html page, loading a React app using Helmet, it seemed my CSS was being re-loaded, causing flashing.
I got around it like this. In the server-page component, a custom attribute:
<link data-block-helmet href=...../>
In the server-rendering script:
const strippedLinks = stripBlockedHelmetTags(helmet.link.toString());
And then the custom function, _stripBlockedHelmetTags_:
let tagArray = tagString.split('/>');
let strippedTagString = tagArray.map((tag)=>{
if(tag.indexOf('data-block-helmet="true"') > -1){
return tag.replace(/data-block-helmet="true" /g, '').replace(/data-react-helmet="true" /g, '');
} else {
return tag;
}
}).join('/>');
return strippedTagString;
Basically strips out the data-react-helmet attribute and Helmet leaves it alone. Let me know if this is useful.
Most helpful comment
As of version 5, Helmet no longer re-creates tags if the server-rendered tags match their client-rendered equivalents. Relevant test: https://github.com/nfl/react-helmet/blob/master/test/HelmetDeclarativeTest.js#L3019-L3040