react-helmet
react-helmet copied to clipboard
Title update lag
I've noticed that there's a bit of a lag between a route changing and the title
property updating. I'm guessing that this is around 200 - 300ms. While minor, it does look just a bit off. I experience this in both my project and also running the react-helmet-example. Are there any suggestions about reducing this lag? If not, is there any known faster way to update the document's title?
@alukach if your component tree is rather deep, then that could cause more delay, but in general we are at the mercy of the DOM's update latency. Although, we are due for some performance metrics for Helmet because we may be able to optimize more. I'll mark this as a todo to measure performance and see if there's a way to optimize.
It also seems to be on render, but if it were before mount I'd reckon it'd be quicker. My document tree is very small but I'm still seeing a noticeable delay.
Admittedly though, I did try it with document.title = xyz
in componentWillMount
so perhaps it's not the fault of this module at all...
This is probably out of the scope of this library, but I thought I'd pop in a note of where this is problematic: Analytics.
I am sending Google Tag Manager events on history change, and the events getting sent to Google Analytics are always off-by-one on the URL <-> Browser Title relationship.
Hooks I've tried in my setup:
-
history.listen()
: Fires before the title is updated -
<Route onChange/>
: Fires before the title is updated -
componentDidUpdate()
: Fires before the title is updated
The only hook I've found where I can get the correct timing is in <Helmet onChangeClientState/>
but I then need to coordinate that with other callbacks to ensure analytics calls are made only at the right times.
To note again: I don't actually think this is helmet's problem, but I probably won't be the last person to hit a wall here and wanted to leave some information behind.
I had same issue.
It looks to me that this delay is caused by adding support for requestIdleCallback
in version 5.
This change https://github.com/nfl/react-helmet/commit/b22e2f4075971f8b80568cd9911a2143f602add1 should also resolve this issue because it will be possible to disabling requestIdleCallback
by using defer={false}
prop.
But for now downgrading to 4.0.0
solved issue for me.
I'm running into this exact issue with PIwik Analytics as well. It will capture the previous document title since it triggers on history change.
I'm hoping that what @adam187 said really does fix this issue.
@dpehrson Ah, hah! I'm so glad you posted about this with regard to analytics problems.
We recently upgraded from react-helmet
v3.2.3 to v5.2.0 in preparation for React v16 and noticed some funky off-by-one-page issues with the tracking events we send to Google Analytics.
For now, we temporarily resolved it by wrapping our tracking functions inside a setTimeout
call with a delay of 0 ms -- this ends up forcing the included function to run after the current event loop is completed:
trackCurrentPage() {
return (dispatch) => {
setTimeout(() => {
dispatch(AnalyticsActions.track.resetPageCustomVars());
dispatch(AnalyticsActions.track.deviceType());
dispatch(AnalyticsActions.track.user());
dispatch(AnalyticsActions.sendPageViewToGA());
}, 0);
};
}
I solved this by adding a variable to my component class called shouldTrackPageview
that gets set to true
in componentDidUpdate
, and the value is checked in the callback for onChangeClientState
. If the value is true
, then it sets the value to false
(to prevent double-firing the event) and then it executes the logic to send the pageview to Google Analytics.
I tried the defer
method mentioned above, but it didn't solve the issue for me.
defer
didn't really work for me too. I was using autotrack so my URL changes were handled automatically. This was what I did to get it to work for me:
// Added this hack:
window.gaplugins.UrlChangeTracker.prototype.handleUrlChange = function(historyDidUpdate) {
window.requestIdleCallback(() => {
setTimeout(() => {
origHandleUrlChange.call(this, historyDidUpdate);
}, 100);
});
};
window.ga('create', config.googleAnalyticsId, 'auto');
window.ga('require', 'eventTracker');
window.ga('require', 'outboundLinkTracker');
window.ga('require', 'urlChangeTracker');
window.ga('send', 'pageview');
In fact, UrlChangeTracker.handleUrlChange()
's implementation is already made async via setTimeout(..., 0)
but it's still insufficient. A timeout of 100ms delays its invocation sufficiently long enough for React to do its stuff.
Why 100ms? It's an arbitary value actually. It's short enough to not miss any page change event, but long enough for React to complete its rendering. This works well enough for most cases.
Seeing something similar to this problem, but not as a result of analytics.
I have a script I run locally against my site. This script hits all key pages in the sitemap, as well a few odd cases (301s, 404s, 400s, and 500s). We run this script on every commit (against a baseline) to ensure we have no SEO regressions or unexpected 500s or what have you
After switching to react-helmet, the script is off-by-one. What i mean by this is that no page when tested individually returns incorrect tags, but when tested as a group, I often get undefined back on the first test, with each subsequent test being behind 1 url behind (so that the 2nd test returns the correct seo tags for the 1st test, which obviously fails the 2nd test). If there is some inexplicable intentional ms delay, then I guess this is to be expected, but it doesn't make any sense to me. All my script does is hit a url, get the html back, and then uses cheerio to scrape the page and compare against the baseline
Why would react-helmet be set up this way? Seems like it would be a disaster for any SEO crawler
Hi, I got this issue as well at the moment. Is there any good or correct solution ??
Downdreading to version 4 when using React 16 created errors with prototypes. And after changing this to see if this helps created new errors.
I see that this issue is quite popular and people are moving away from Helmet just to sort this issue.
Are you planning to address this issue?? Cause if not I will need to use something else as well??
Removing the enhancement tag and escalating to a bug. We are in the process of discussing the roadmap for the next update major update and will be addressing some of these bugs.
@tmbtech Hi. Thanks for the quick replay. I think this is a major disadvantage of your class. Everyone Is now want to have Analytics and Google stuff connected right for their marketing purposes and this puts your class back in the pack but it works ok for any other purpose.
I think the solution to this one will somehow connect it to the Router and apply changes to head before the path will change. I know this sounds weird but I think this will prevent for having head data behind a change of URL for sure.
I will love to see this done and especially you did not have any publish for a year according to npm and you still have crazy numbers of downloads weekly (~300k). I think this puts you guys in responsibility to keep this up to date. Especially that react is growing fast.
Regards and I will check up on this issue :)
Thanks for promoting this and pushing this forwards :) Keep up the good work :)
Alot of overkill fixes on this thread, you can set the title tag easily through window.document.title
and its immediate.
what happened to this issue?
Reading through the solutions above, none were quite right for what I needed. An arbitrary delay is insufficient, as for us the page title is dependent on the results of an asynchronous API call.
I'm using react-helmet
on every page to change various data in the header, including the title. I stopped using react-piwik
's router connection, and instead use a manually invoked function. The component below is rendered within the application, at the root level. I have simplified the code below to include only what is necessary. Hope it helps someone.
import React from 'react';
import Piwik from 'react-piwik';
import { Helmet } from 'react-helmet';
new Piwik({
url: 'https://analytics.example.com', // insert your analytics URL here
siteId: 1,
trackErrors: true,
});
Piwik.push(['enableHeartBeatTimer']);
let lastPath = null;
const onHelmetChange = ({ metaTags }) => {
if (
'undefined' !== typeof window &&
lastPath !== window.location.pathname &&
metaTags.filter(m => m.name === 'page-loaded' && m.content === 'true').length > 0
) {
if (lastPath !== null) {
Piwik.push(['setReferrerUrl', `${window.location.origin}${lastPath}`]);
}
Piwik.push(['setDocumentTitle', document.title]);
Piwik.push(['setCustomUrl', window.location.href]);
Piwik.push(['trackPageView']);
lastPath = window.location.pathname;
}
}
export default () => (
<Helmet onChangeClientState={onHelmetChange}>
<meta name="page-loaded" content="false" />
</Helmet>
)
then on each page, when I set the metadata using Helmet, I also set page-loaded
to true
, like the following:
<Helmet>
<meta name="page-loaded" content="true" />
</Helmet>
The same approach can be used to trigger Google Analytics or any other events on true page load. Make sure you set page-loaded
to true
on each page else it won't work - in our architecture, this was a simple solution. This works because Helmet switches back to its default between page loads, hence resetting page-loaded
to false
until the next page is rendered.
Did someone resolved this issues using react-tag-manger ? I would like to have some feedback and maybe an example
I'm having the same problem with the document title sent out in analytics lagging one behind.
Still the same problem in google analytics. Any news about this bug ? Thanks
We are still having issues with this, title always showing one behind from url on GA. Any news on this please?
I've tried for a bit to think in a good solution, but there are only two solutions that I can think of:
- A package on top of the react-helmet should be created as a combination with GA.
- Use something like react-ga, but either way, some work would be needed because to send the tracking it would need to wait for the title change on page change.
As I'm a bit out of schedule, for now, my solution was to use an abstraction that I had for SEO with ReactHelmet to manage the tracking of all pages.
When onChangeClientState
is triggered:
if (prevPathname !== window.location.pathname) {
analytics.onPageChange();
prevPathname = window.location.pathname;
}
To handle this, in my useEffect I gave a setTimeout of ~750-1000ms to execute ReactGA.pageview(), like :
useEffect(() => {
setTimeout(() => {
ReactGA.pageview(window.location.pathname);
}, 1000);
})
However, I'm still looking for a cleaner solution.
I'm having the same problem when implementing Segment tracking on a React SPA.
Removing the enhancement tag and escalating to a bug. We are in the process of discussing the roadmap for the next update major update and will be addressing some of these bugs.
Is there any update on this?
This is still a major issue that could lead to my project migrating away from react-helmet.
BUMP!