Does anyone know if there's a possibility to set truly dynamic meta tags per page in a React App without Server Side Rendering?
In a project that I am building I have some pages with a route like / article / {Id} and I would like to define dynamic meta tags (title, image, description). I use a reaction helmet as a component but it doesn't work here is the code of my component, part of the code page article / {id}, and my page index.html
index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta property="og:title" content="title" data-rh="true">
<meta property="og:description" content="description" data-rh="true">
<meta property="og:image" content="icon%20maracana%20app.png" data-rh="true">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic" rel="stylesheet"
type="text/css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-173374516-1"></script>
<script data-ad-client="ca-pub-7237319988145838" async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'UA-173374516-1');
</script>
<!-- <script type="text/javascript" src="js/my_script.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/​moment.js/2.19.1/moment.min.js"></script>
</head>
<body>
<!-- Plugin Comments -->
<div id="fb-root"></div>
<script async defer crossorigin="anonymous"
src="https://connect.facebook.net/fr_FR/sdk.js#xfbml=1&version=v9.0&appId=357191748915887&autoLogAppEvents=1"
nonce="QVCodNV8"></script>
<!-- ---------------- -->
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
component:
import React from "react";
import PropTypes from "prop-types";
import { Helmet } from "react-helmet";
import { IMAGES_LINK, API_LINK } from '../../utils/constants'//const metaDecorator = require("../../data/metaDecorator");const MetaDecorator = ({ title, description, imageUrl, imageAlt }) => {
if (title != undefined & description != undefined & imageUrl != undefined & imageAlt != undefined) {
return (
<Helmet><title>{title}</title><meta property="og:title" content={title} /><meta name="description" content={description} /><meta property="og:description" content={description} /><meta property="og:image" content={API_LINK + imageUrl} /><metaproperty="og:url"content={"https://maracanafoot.com" + window.location.pathname + window.location.search}
/><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:image:alt" content={imageAlt} />
{/* <meta name="twitter:site" content={metaDecoratortwitterUsername} /> */}
</Helmet>
);
} else {
return (
<Helmet></Helmet>
);
}
}
MetaDecorator.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
imageUrl: PropTypes.string.isRequired,
imageAlt: PropTypes.string.isRequired,
};
export default MetaDecorator;
article page :
render = () => {
const s = this.state;
return (<><div>
{this.state.loadingArticle ? <><br /><div style={this.styleSpinner} className='mt-3 mb-3'><ImpulseSpinner size={30} color="#208FDF" loading={this.state.loadingArticle} /></div></>
: null}
{!this.isEmpty(this.state.article) ? <><MetaDecoratordescription={this.state.article.resumer}title={this.state.article.title}imageUrl={this.state.article.image}imageAlt="image alt"
/>
Thanks in advance for any hint!
If you are not using server-side rendering, you can still change meta tags dynamically in a React app by using JavaScript to update the head element of the page.
You can create a helper function to update the meta tags in the head element based on the current page. For example:
function updateMetaTags(title, description, imageUrl, imageAlt) { const metaTitle = document.querySelector('meta[property="og:title"]'); const metaDescription = document.querySelector('meta[name="description"]'); const metaImageUrl = document.querySelector('meta[property="og:image"]'); const metaImageAlt = document.querySelector('meta[name="twitter:image:alt"]'); metaTitle.setAttribute("content", title); metaDescription.setAttribute("content", description); metaImageUrl.setAttribute("content", imageUrl); metaImageAlt.setAttribute("content", imageAlt); }
Then, in your component for the article page, you can call the updateMetaTags function with the appropriate values:
import React, { Component } from "react"; import PropTypes from "prop-types"; import { IMAGES_LINK, API_LINK } from '../../utils/constants'import { ImpulseSpinner } from "react-spinners-kit"; import { Helmet } from "react-helmet"; class ArticlePage extends Component { // ...componentDidMount() { this.updateMetaTags(); } componentDidUpdate(prevProps) { if (this.props.articleId !== prevProps.articleId) { this.updateMetaTags(); } } updateMetaTags() { const { article } = this.state; const title = article.title; const description = article.resumer; const imageUrl = API_LINK + article.image; const imageAlt = "image alt"; updateMetaTags(title, description, imageUrl, imageAlt); } render() { // ... } } ArticlePage.propTypes = { articleId: PropTypes.string.isRequired, }; export default ArticlePage;
Note that the updateMetaTags function assumes that your meta tags have specific property and name attributes, so make sure they match the ones in your index.html file.
Also, you can continue to use react-helmet for any other meta tags that don't need to be dynamically updated.