My program (https://rohanweb.netlify.app) is sanity API driven. It has blog post so whenever I share particular blog(using react-share), It displays default meta description and image which is inside index.html
file. I have used React Helmet for dynamic meta tags but is doesn't seem to be working. No matter what I share, It is displaying default meta
and when I remove that from index.html
file it displays nothing. I have checked from https://heymeta.com . Here is sample of code for :
<Helmet>
<title>{singlePost.blogTitle}</title>
<link rel="canonical" href={window.location.href} />
<meta property="og:url" content={window.location.href} />
<meta property="og:type" content="website" />
<meta name="twitter:card" content={singlePost.publicImg.asset.url} />
//for Title
<meta property="og:title" content={singlePost.blogTitle} />
<meta itemprop="name" content={singlePost.blogTitle} />
<meta name="twitter:title" content={singlePost.blogTitle}/>
//for Description
<meta property="og:description" content={singlePost.blogDescription} />
<meta itemprop="description" content={singlePost.blogDescription} />
<meta name="twitter:description" content={singlePost.blogDescription} />
//for Image
<meta property="og:image" content={singlePost.publicImg.asset.url} />
<meta itemprop="image" content={singlePost.publicImg.asset.url} />
<meta name="twitter:image" content={singlePost.publicImg.asset.url} />
</Helmet>
React-helmet is not ideal for the solution required. Below is the order in which the browser handles it
Having your application hosted on a server, the default meta-tags are rendered as fetched. It changes only when a browser requests for a resources on a page, after which the react-helmet functions are executed.
A Better solution that I could think of would be to configure meta-tags from the server and Hydrate at the front-end.
Example Below,
<html>
<head>
__PLACEHOLDER_FOR_DYNAMIC_META_TAG__
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
Read the index synchronously and replace the placeholder with meta-tag needed
const path = require("path")
const express = require("express")
const app = express()
const fs = require("fs")
const indexFilePath= path.join(__dirname, "build/index.html")
app.get("/", (req, res) => {
const myFile = fs.readFileSync(indexFilePath)
const myMetaTag= "Meta tag details as per requirement"
const toHydrate = myFile.replace("__PLACEHOLDER_FOR_DYNAMIC_META_TAG__", myMetaTag)
res.send(toHydrate)
});
app.get("*", (req, res) =>
res.sendFile(path.join(__dirname, "build/index.html"))
)
const port = process.env.PORT || 5000
app.listen(port, () => {
console.log(`Server listening on port ${port}`)
});
In your react app instead of ReactDOM.render(<App/>, ...) use ReactDOM.hydrate(<App />, ...)
Or simply go for Next.js :)
Updated answer for your comment below,
document.getElementsByTagName('meta')["keywords"].content = "Hello";
document.getElementsByTagName('meta')["description"].content = "description";