【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)
発生している問題・エラー(スクショ p3)
該当するソースコード
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