TaikiTkwkbysh
@TaikiTkwkbysh (WAKA Engineer)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【Next.js / microCMS 】通常のサイトを埋め込み編集し、リンクカードで表示させたい。

microCMSの「埋め込みプレビュー」で通常のサイトを設定し、リンクカードとして表示させたいです。

MicsoCMSを利用してブログサイトを作成しているのですが、新リッチエディタの埋め込み編集を利用すると、以下のようなエラーが発生してしまいます。

発生している問題・エラー①

client.js:1 Warning: Expected server HTML to contain a matching <a> in <div>.
    at a
    at div
    at div
    at ConvertBody (webpack-internal:///./components/ContentStyle/ConvertBody.js:21:11)
    at div
    at PostBody (webpack-internal:///./components/ContentStyle/PostBody.jsx:20:11)
    at div
    at _c (webpack-internal:///./components/Container/main-container.tsx:12:11)
    at TestPage (webpack-internal:///./pages/blog/Testpage.tsx:35:11)
    at MyApp (webpack-internal:///./pages/_app.tsx:12:11)
    at PathnameContextProviderAdapter (webpack-internal:///./node_modules/next/dist/shared/lib/router/adapters.js:62:11)
    at ErrorBoundary (webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:303:63)
    at ReactDevOverlay (webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:852:919)
    at Container (webpack-internal:///./node_modules/next/dist/client/index.js:62:1)
    at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:172:11)
    at Root (webpack-internal:///./node_modules/next/dist/client/index.js:347:11)

発生している問題・エラー②

react-dom.development.js:12507 Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
    at throwOnHydrationMismatch (react-dom.development.js:12507:1)
    at tryToClaimNextHydratableInstance (react-dom.development.js:12535:1)
    at updateHostComponent (react-dom.development.js:19902:1)
    at beginWork (react-dom.development.js:21618:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
    at invokeGuardedCallback (react-dom.development.js:4277:1)
    at beginWork$1 (react-dom.development.js:27451:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
    at renderRootSync (react-dom.development.js:26434:1)
    at performConcurrentWorkOnRoot (react-dom.development.js:25738:1)
    at workLoop (scheduler.development.js:266:1)
    at flushWork (scheduler.development.js:239:1)

発生している問題・エラー(スクショ p1~2)

スクリーンショット 2023-07-24 17.43.40.png

発生している問題・エラー(スクショ p3)

スクリーンショット 2023-07-24 17.44.32.png

該当するソースコード

TestPage.tsx

import { getPostBySlug } from "../../lib/api";
import Header from "../../components/Header/Header";
import MainContainer from "../../components/Container/main-container";
import type { props } from "../../types/props/propsType";
import PostHeader from "../../components/Header/PostHeader";
import useHeaderScroll from "../../hooks/useHeaderScroll";
import Image from "next/legacy/image";
import { PostBody } from "../../components/ContentStyle/PostBody";
import ConvertBody from "../../components/ContentStyle/ConvertBody";
import "highlight.js/styles/hybrid.css";
import dynamic from "next/dynamic";
import { useEffect } from "react";


const TestPage = ({ title, publish, content, eyecatch, categories }: props) => {

  const styles = {
    margin: "0px",
    width: "100%",
  };

  return (
    <>
      <Header isActive={isHeaderActive} />
      <MainContainer>
        <article>
          <PostHeader title={title} subTitle="Blog Article" publish={publish} />
          <figure style={styles}>
            <Image
              src={eyecatch.url}
              alt=""
              width={eyecatch.width}
              height={eyecatch.height}
              layout="responsive"
              sizes="(max-width: 800px)"
              priority
            />
          </figure>
        </article>

        {/* 問題の箇所 */}
        <PostBody>
          <ConvertBody contentHTML={content} />
        </PostBody>
      </MainContainer>
    </>
  );
};

export default TestPage;

export async function getStaticProps() {
  const slug = "technology";

  const post = await getPostBySlug(slug);

  return {
    props: {
      title: post.title,
      publish: post.publishDate,
      content: post.content,
      eyecatch: post.eyecatch,
      categories: post.categories,
    },
  };
}

PostBody.jsx

import { ReactNode } from "react";
import styles from "./postBody.module.css";
import { useEffect } from "react";

export const PostBody = ({ children }) => {
  useEffect(() => {
    if (window && window.iframely) {
      window.iframely.load();
    }
  });
  return <div className={styles.stack}>{children}</div>;
};

ConvertBody.js

import parse, { DOMNode } from "html-react-parser";
import Image from "next/legacy/image";
import { HTMLReactParserOptions, Element } from "html-react-parser";
import hljs from "highlight.js";

export const ConvertBody = ({ contentHTML }) => {
  const contentReact = parse(contentHTML, {
    replace: (domNode) => {
      if (domNode instanceof Element && domNode.attribs) {
        if (domNode.name === "img") {
          const { src, alt, width, height } = domNode.attribs;
          return (
            <Image
              layout="responsive"
              src={src}
              width={changeWidth}
              height={changeHeight}
              alt={alt}
              sizes="(max-width: 1200px)"
            />
          );
        } else if (domNode.name === "pre") {
          const code = domNode.children[0].children[0].data; // pre配下のcode(インラインコードは反映しない)
          const highlightCode = hljs.highlightAuto(code); // ハイライトのスタイル
          return (
            <pre>
              <code className="hljs">{parse(highlightCode.value)}</code>
            </pre>
          );
        }
      }
    },
  });
  return <>{contentReact}</>;
};

export default ConvertBody;

環境・その他

package.json

{
  "name": "blogs",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "cheerio": "^1.0.0-rc.12",
    "date-fns": "^2.30.0",
    "highlight.js": "^11.8.0",
    "html-react-parser": "^4.2.0",
    "microcms-js-sdk": "^2.5.0",
    "next": "13.2.4",
    "react": "18.2.0",
    "react-dom": "^18.2.0",
    "react-icons": "^4.8.0",
    "styled-components": "^6.0.5"
  },
  "devDependencies": {
    "@types/node": "18.15.0",
    "@types/react": "18.0.28",
    "@types/react-dom": "18.0.11",
    "eslint": "8.36.0",
    "eslint-config-next": "13.2.4",
    "eslint-config-prettier": "^8.8.0",
    "typescript": "4.9.5"
  }
}


埋め込み表示したいサイト



自分で試したこと

ConvertBodyコンポーネントをnext/dynamicを利用し、SSRを無効にした結果、エラーは出なくなったが埋め込み編集のものがブラウザに表示されなくなった。

ConvertBodyコンポーネントの戻り値をdivタグに変更し、redct-domのsuppressHydrationWarning={true}を設定してみたが、解消されなかった。

microCMSに直接問い合わせもしてみたのですが、以下のサイトのリンクを共有されたのみで具体的な解決案を教えてもらえるに至らず。

React18+Next.jsにおけるHydration failedについて

Text content does not match server-rendered HTML | Next.js

0

No Answers yet.

Your answer might help someone💌