Razzle with React Helmet: метатеги неправильно отображаются в сканерах при использовании динамических значений из Axios
Я использую Razzle для использования React и рендеринга на стороне сервера с React Helmet. У меня есть эта проблема, когда вы используете React Helmet для установки метатегов с динамическими значениями, они отображаются неправильно. Но это работает, если вы установите метатеги со статическими значениями.
Пожалуйста, взгляните на некоторые коды.
SEO.js Компонент
import React, { Component } from 'react';
import { Helmet } from "react-helmet-async";
class SEO extends Component {
constructor(props) {
super(props);
this.state = {
title: this.props.title,
description: this.props.description,
image: this.props.image
}
}
shouldComponentUpdate(nextProps) {
if(this.props != nextProps) {
this.setState({
title: nextProps.title,
description: this.props.description,
image: nextProps.image
})
return true;
} else {
return false;
}
}
render() {
return (
<div>
<Helmet>
<title>{this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"}</title>
<meta name="title" content={this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"} />
<meta
name="description"
content={this.state.description ? this.state.description : "Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia."}
/>
<meta
property="og:title"
content={this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"}
/>
<meta
property="og:description"
content={this.state.description ? this.state.description : "Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia."}
/>
<meta
property="og:image"
content={this.state.image ? this.state.image : "https://volunteerhub.id/assets/logo/seo.jpg"}
/>
<meta property="og:url" content="https://volunteerhub.id" />
<meta
name="twitter:title"
content={this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"}
/>
<meta
name="twitter:description"
content={this.state.description ? this.state.description : "Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia."}
/>
<meta
name="twitter:image"
content={this.state.image ? this.state.image : "https://volunteerhub.id/assets/logo/seo.jpg"}
/>
<meta name="twitter:card" content="summary_large_image" />
</Helmet>
</div>
);
}
}
export default SEO;
Вот пример настройки статических метатегов:
import React, {Component} from "react";
import SEO from "../../components/SEO";
class ScheduleContainer extends Component {
constructor(props) { super(props); }
render() {
return(
<div>
<SEO
title="Cek Jadwal | Volunteer Hub by Indorelawan"
description="Cek jadwal kegiatan di Volunteer Hub! Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia." />
</div>);
}
}
А вот пример настройки динамических метатегов:
import React, {Component} from "react";
import axios from "axios";
import SEO from "../../components/SEO";
class EventContainer extends Component {
constructor(props) {
super(props);
this.state = {
event: {}
}
}
componentDidMount() {
axios.get('API_URL')
.then(response => {
this.setState({ event: response.data.result })
});
}
render() {
return(
<div>
<SEO
title={this.state.event.title}
description={this.state.event.description} />
</div>);
}
}
Server.js
import RootContainer from "./containers/RootContainer";
import React from "react";
import { StaticRouter } from "react-router-dom";
import express from "express";
import { renderToString } from "react-dom/server";
import { Helmet, HelmetProvider } from "react-helmet-async";
const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);
const server = express();
server
.disable("x-powered-by")
.use(express.static(process.env.RAZZLE_PUBLIC_DIR))
.get("/*", (req, res) => {
const context = {};
const helmetContext = {};
const markup = renderToString(
<HelmetProvider context={helmetContext}>
<StaticRouter context={context} location={req.url}>
<RootContainer />
</StaticRouter>
</HelmetProvider>
);
const { helmet } = helmetContext;
if (context.url) {
res.redirect(context.url);
} else {
res.status(200).send(
`<!doctype html>
<html lang="">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta
name="keywords"
content="volunteer, hub, by, indorelawan, volunteer hub, volunteer hub by indorelawan, kolaborasi, dimulai, dari, sini, ubah, niat, baik, jadi, aksi, baik, hari, ini"
/>
<meta name="robots" content="index, follow" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="language" content="Indonesia" />
<meta name="author" content="Indorelawan" />
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="theme-color" content="#222222" />
${helmet.title.toString()}
${helmet.meta.toString()}
${
assets.client.css
? `<link rel="stylesheet" href="${assets.client.css}">`
: ""
}
${
process.env.NODE_ENV === "production"
? `<script src="${assets.client.js}" defer></script>`
: `<script src="${
assets.client.js
}" defer crossorigin></script>`
}
...
</head>
<body>
<div id="root">${markup}</div>
<script>
if ("serviceWorker" in navigator) {
if (navigator.serviceWorker.controller) {
console.log("[PWA Builder] active service worker found, no need to register");
} else {
// Register the service worker
navigator.serviceWorker
.register("pwabuilder-sw.js", {
scope: "./"
})
.then(function (reg) {
console.log("[PWA Builder] Service worker has been registered for scope: " + reg.scope);
});
}
}
</script>
</body>
</html>`
);
}
});
export default server;
Теперь, когда вы увидели код, вот результат, который я скопировал и вставил в Google SERP Simulator и WhatsApp:
Статические метатеги являются результатом страницы расписания:
Google SERP Simulator WhatsApp
Динамические метатеги являются результатом страницы событий:
Google SERP Simulator WhatsApp
Исходя из результата, он всегда возвращает заголовок и описание тега по умолчанию, а не заголовок и описание, переданные из Axios. Это нормальное поведение или я делаю что-то не так?
0 ответов
Рендеринг на стороне сервера Razzle IS, проблема с вашим сценарием динамических метатегов заключается в том, что вы полагаетесь на данные, которые извлекаются в componentDidMount, а componentDidMount, как метод жизненного цикла из фазы фиксации, не вызывается на сервере, поскольку нет фактического установка на стороне сервера.
NextJS решает эту проблему за вас благодаря getInitialProps, который вызывается на сервере и клиенте.
Turns out Razzle is not Server Side Rendering. Either you have to define the SEO tags using a custom express server, or just use SSR for React.
I am using NextJS for this and this is a no problem.