Я использую Раззл для использования React и рендеринга на стороне сервера с Реагировать Шлем. У меня есть эта проблема, когда вы используете 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>);
}
}
Сервер.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.info("[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.info("[PWA Builder] Service worker has been registered for scope: " + reg.scope);
});
}
}
</script>
</body>
</html>`
);
}
});
export default server;
Теперь, когда вы видели код, вот результат, когда я скопировал его в Google SERP Simulator и WhatsApp:
Статические метатеги получаются из Страница расписания:
Симулятор поисковой выдачи Google WhatsApp
Динамические метатеги являются результатом Страница события:
Симулятор поисковой выдачи Google WhatsApp
В результате он всегда возвращает тег заголовка и описания по умолчанию, а не заголовок и описание, переданные из axios. Это нормальное поведение или я что-то не так делаю?
🤔 А знаете ли вы, что...
React обеспечивает реактивное обновление интерфейса при изменении состояния.
Оказывается, Razzle не является рендерингом на стороне сервера. Либо вам нужно определить теги SEO с помощью специального экспресс-сервера, либо просто использовать SSR для React.
Я использую NextJS для этого, и это не проблема.
При рендеринге на стороне сервера Razzle IS проблема с вашим сценарием динамических метатегов заключается в том, что вы полагаетесь на данные, которые извлекаются в componentDidMount, а componentDidMount, как метод жизненного цикла на этапе фиксации, не вызывается на сервере, поскольку нет фактического монтаж на стороне сервера.
NextJS решает эту проблему благодаря getInitialProps, который вызывается на сервере и клиенте.