Here is, at least in my opinion, a cleaner way to write the google tag manager component:
import React, {Fragment} from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";
import gtmParts from "react-google-tag-manager";
const GoogleTagManager = ({gtmId, dataLayerName, events, previewVariables}) => {
const gtm = gtmParts({id: gtmId, dataLayerName, events, previewVariables});
const gtmNode = !window[dataLayerName]
? ReactDOM.createPortal(gtm.scriptAsReact(), document.head)
: undefined;
return (
<Fragment>
{gtmNode}
{gtm.noScriptAsReact()}
</Fragment>
);
};
GoogleTagManager.propTypes = {
gtmId: PropTypes.string.isRequired,
dataLayerName: PropTypes.string,
events: PropTypes.shape(),
previewVariables: PropTypes.string,
};
GoogleTagManager.defaultProps = {
dataLayerName: "dataLayer",
events: {},
previewVariables: "",
};
export default GoogleTagManager;
It would work if your scriptAsReact() method returned the javascript code as-is instead of a string which script content need to be retrieved and eval() (ie in the code above, replacing gtm.scriptAsReact() by the script would work fine).
Would you mind adapting the method, or simply add another one to the GtmParts that'll only return the js code ?
Note that Google Tag Manager documentation recommends to set the script in the head element, not the body, which is why I'm using Fragment.
Here is, at least in my opinion, a cleaner way to write the google tag manager component:
It would work if your
scriptAsReact()method returned the javascript code as-is instead of a string which script content need to be retrieved andeval()(ie in the code above, replacinggtm.scriptAsReact()by the script would work fine).Would you mind adapting the method, or simply add another one to the GtmParts that'll only return the js code ?
Note that Google Tag Manager documentation recommends to set the script in the head element, not the body, which is why I'm using Fragment.