Razzle with React Helmet: метатеги неправильно отображаются в сканерах при использовании динамических значений из Axios

Я использую Раззл для использования 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 Razzle with React Helmet: метатеги неправильно отображаются в сканерах при использовании динамических значений из Axios WhatsApp Razzle with React Helmet: метатеги неправильно отображаются в сканерах при использовании динамических значений из Axios

Динамические метатеги являются результатом Страница события:

Симулятор поисковой выдачи Google Razzle with React Helmet: метатеги неправильно отображаются в сканерах при использовании динамических значений из Axios WhatsApp Razzle with React Helmet: метатеги неправильно отображаются в сканерах при использовании динамических значений из Axios

В результате он всегда возвращает тег заголовка и описания по умолчанию, а не заголовок и описание, переданные из axios. Это нормальное поведение или я что-то не так делаю?

🤔 А знаете ли вы, что...
React обеспечивает реактивное обновление интерфейса при изменении состояния.


3
1 520
2

Ответы:

Оказывается, Razzle не является рендерингом на стороне сервера. Либо вам нужно определить теги SEO с помощью специального экспресс-сервера, либо просто использовать SSR для React.

Я использую NextJS для этого, и это не проблема.


Решено

При рендеринге на стороне сервера Razzle IS проблема с вашим сценарием динамических метатегов заключается в том, что вы полагаетесь на данные, которые извлекаются в componentDidMount, а componentDidMount, как метод жизненного цикла на этапе фиксации, не вызывается на сервере, поскольку нет фактического монтаж на стороне сервера.

NextJS решает эту проблему благодаря getInitialProps, который вызывается на сервере и клиенте.