Как мне удалить тег скрипта родительского компонента в разметке дочернего компонента layout.tsx?

Вопрос или проблема

Я использую маршрутизатор приложений из next.js.
Я хотел бы добавить данные jsonLd для обеих страниц, “/blog” и “/blog/[searchKeyword]”.
Но я столкнулся с некоторыми проблемами в этом процессе.

blog > layout.tsx

 return (
<>
    <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
        id="jsonLd-blog"
    />
    {children}
</> );

blog/[searchKeyword] > layout.tsx

return ( <>
    <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
        id={jsonLd-${params.searchKeyword}}
    />
    {children}
</> );
  1. Во-первых, на странице “/blog/[searchKeyword]” есть не только jsonLd из ее layout.tsx, но и из layout.tsx “/blog”.
  2. Во-вторых, я попытался удалить родительский код скрипта jsonld, используя метод ‘remove()’ с их идентификатором, таким как ‘jsonLd-blog’, как ниже.
"use client";

import { useEffect } from "react";

const RemoveJsonScript: React.FC<{ elementId: string }> = ({ elementId }) => {
  useEffect(() => {
    const oldJsonLds = document.getElementById(elementId);
    if (oldJsonLds) {
      oldJsonLds.remove();
    }
  }, []);

  return <></>;
};

export default RemoveJsonScript;

3. В-третьих, однако это вызывает ошибку ниже, независимо от того, используется ли она в серверном компоненте или клиентском компоненте.

Uncaught NotFoundError: Не удалось выполнить 'removeChild' на 'Node': Узел, который нужно удалить, не является дочерним этого узла.

4. Кроме того, это не работает в теге <Head> из “next/head”, а только в теге <head>. Эта проблема не связана с вышеупомянутыми тремя проблемами, но мне интересно, почему это так.

Я не знаю, как решить эту проблему. Next.js – это самый великое фреймворк для SEO, который я когда-либо использовал, но эта ошибка вызывает у меня разочарование. Мне нужна ваша помощь.

Я хочу избавиться от тега скрипта jsonLd родителя, без каких-либо сообщений об ошибках, таких как ‘Uncaught NotFoundError: Не удалось выполнить ‘removeChild’ на ‘Node’: Узел, который нужно удалить, не является дочерним этого узла.’

Это поведение ожидаемо, так как layout.tsx будет оборачивать все свои дочерние макеты или страницы. Таким образом, если у вас есть /blog/layout.tsx и /blog/[searchKeyword]/layout.tsx, дерево компонентов для /blog/[searchKeyword]/page.tsx будет выглядеть так:

<BlogLayout>
  <BlogSearchKeywordLayout>
    <BlogSearchKeywordPage />
  </BlogSearchKeywordLayout>
</BlogLayout>

Лучшее решение для вас – разместить свои теги скриптов json-ld в /blog/page.tsx и /blog/[searchKeyword]/page.tsx

Ответ или решение

Чтобы устранить проблему с повторяющимся тегом <script> для JSON-LD в компоненте Next.js, есть несколько моментов, которые необходимо учесть. Давайте рассмотрим решение по шагам.

Описание проблемы

Ваша структура маршрутов Next.js включает общий родительский компонент (/blog/layout.tsx), который создает тег JSON-LD, и дочерний компонент (/blog/[searchKeyword]/layout.tsx), который тоже создает свой собственный тег JSON-LD. В итоге при загрузке маршрута /blog/[searchKeyword] у вас оказывается два тега JSON-LD: один от родительского компонента и второй от дочернего.

Ошибка

Вы попытались удалить родительский тег JSON-LD с помощью метода remove(), но столкнулись с ошибкой Uncaught NotFoundError. Это связано с тем, что когда вы пытаетесь удалить элемент, он не является дочерним каким-либо узлом, что приводит к этой ошибке.

Решение

1. Перемещение тегов JSON-LD

Наиболее простым и эффективным решением будет переместить создание тегов JSON-LD в компоненты страниц, а не в компоненты макета. Так каждый компонент страницы будет отвечать за свой собственный вывод данных. В результате вы избежите конфликта между родительским и дочерним тегами.

// blog/page.tsx
export default function BlogPage() {
  const jsonLd = { /* ваши данные JSON-LD */ };
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
        id="jsonLd-blog"
      />
      {/* Остальной код страницы */}
    </>
  );
}

// blog/[searchKeyword]/page.tsx
export default function BlogSearchKeywordPage({ params }) {
  const jsonLd = { /* ваши данные JSON-LD для конкретного поиска */ };
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
        id={`jsonLd-${params.searchKeyword}`}
      />
      {/* Остальной код страницы */}
    </>
  );
}

2. Удаление тега JSON-LD через эффект

Если по какой-то причине вы все же хотите оставить теги JSON-LD в макетах и только удалять их в дочернем компонентах, то можно использовать следующий подход:

// blog/[searchKeyword]/layout.tsx
"use client";

import { useEffect } from "react";

const BlogSearchKeywordLayout = ({ children }) => {
  useEffect(() => {
    const scriptId = 'jsonLd-blog';
    const oldJsonLd = document.getElementById(scriptId);
    if (oldJsonLd) {
      oldJsonLd.remove();
    }
  }, []);

  return <>{children}</>;
};

export default BlogSearchKeywordLayout;

Объяснение проблемы с <Head>

Что касается вашего вопроса о том, почему next/head не работает так, как вы ожидаете, это связано с тем, что next/head управляет содержимым <head> в рендеринге и не удаляет элементы, которые были добавлены в предыдущих рендерах. Теги, добавленные напрямую в компонент, будут присутствовать в DOM, пока не будут удалены вручную. Это объясняет, почему вы видите теги <script> в некомпилированном виде.

Итог

Наилучший способ устранить дублирование тегов JSON-LD – это поместить их в конкретные страницы, как показано выше. Это не только устранит проблему, но и улучшит читаемость и mantenimiento кода.

Если у вас остались вопросы или требуются дополнительные разъяснения, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...