質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

MicroCMS

MicroCMSとは、APIベースのヘッドレスCMSです。日本製のため、デフォルトで日本語に対応しており、サポートも豊富。管理画面でも作成したコンテンツなどが見やすくシンプルで、APIの管理がしやすい点も特徴です。

JAMstack

JAMstackは、JavaScript・API・Markupの頭文字を取ったWebアプリケーションアーキテクチャです。事前に構築されたHTMLをCDN上で配信。高いパフォーマンスとセキュリティが特徴です。

Twitter

Twitterは、140文字以内の「ツイート」と呼ばれる短文を投稿できるサービスです。Twitter上のほぼ全ての機能に対応するAPIが存在し、その関連サービスが多く公開されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

287閲覧

Next.js×microCMSで構築中のブログに、Twitterの埋め込みが正常に表示されない

alolo

総合スコア9

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

MicroCMS

MicroCMSとは、APIベースのヘッドレスCMSです。日本製のため、デフォルトで日本語に対応しており、サポートも豊富。管理画面でも作成したコンテンツなどが見やすくシンプルで、APIの管理がしやすい点も特徴です。

JAMstack

JAMstackは、JavaScript・API・Markupの頭文字を取ったWebアプリケーションアーキテクチャです。事前に構築されたHTMLをCDN上で配信。高いパフォーマンスとセキュリティが特徴です。

Twitter

Twitterは、140文字以内の「ツイート」と呼ばれる短文を投稿できるサービスです。Twitter上のほぼ全ての機能に対応するAPIが存在し、その関連サービスが多く公開されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2024/05/28 03:38

編集2024/05/28 08:15

実現したいこと

Next.jsとmicroCMSを使ったjamstackブログを構築中。
ブログの記事詳細を表示するためのページとしてNEXTJS/pages/blog/配下に[slug].jsを作成。

microCMSで、記事にTwitterの埋め込みがあるときとないときで挙動が不安定になるため、改善したい。

発生している問題・分からないこと

npx netx devでローカルサーバーでの検証時、以下のような挙動が発生しており、不安定である

前提

  1. microCMSでTwitterの埋め込みのある記事(A・B)と埋め込みのない記事(C)を作成

ローカルサーバー上で見られた挙動

  1. Cに、記事一覧ページ(blog/page/1)などから直接アクセスすると問題なく表示される
  2. Cから、ページネーションを使ってAもしくはBにアクセスすると、記事ページ自体は表示されるがTwitterの埋め込みが表示されない(そのうえで一回ページをリロードすると表示される)
  3. 同様に、AもしくはBに記事一覧ページなどから直接アクセスすると、記事ページ自体は表示されるがTwitterの埋め込みが表示されない(そのうえで一回ページをリロードすると表示される)
  4. AもしくはBで、Twitterの埋め込みが表示されている状態でページネーションを使って前後の記事へ遷移するとエラー発生
  5. AもしくはBのURLをアドレスバーに入れて遷移すると埋め込みが表示される

など、とにかく埋め込みの表示が不安定

エラーメッセージ

error

1【DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.】 2 3【The above error occurred in the <blockquote> component. 4React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.】

該当のソースコード

javascript

1【pages/_document.js】 2import { Html, Head, Main, NextScript } from 'next/document' 3 4import { siteMeta } from 'lib/constants' 5const { siteLang } = siteMeta 6 7export default function Document() { 8 return ( 9 <Html lang={siteLang}> 10 <Head> 11 <script async src="https://platform.twitter.com/widgets.js"></script> 12 </Head> 13 <body> 14 <Main /> 15 <NextScript /> 16 </body> 17 </Html> 18 ) 19} 20

javascript

1【pages/blog/[slug].js】 2import { useEffect, useRef } from 'react' 3import { getPostBySlug, getAllSlugs } from 'lib/api' 4import { extractText } from 'lib/extract-text' 5import { prevNextPost } from 'lib/prev-next-post' 6import Meta from 'components/meta' 7import Container from 'components/container' 8import PostHeader from 'components/post-header' 9import PostBody from 'components/post-body' 10import { 11 TwoColumn, 12 TwoColumnMain, 13 TwoColumnSidebar, 14} from 'components/two-column' 15import ConvertBody from 'components/convert-body' 16import PostCategories from 'components/post-categories' 17import PostTags from 'components/post-tags' 18import Share from 'components/sns-sharebtn' 19import Pagination from 'components/pagination' 20import Image from 'next/image' 21import { getPlaiceholder } from 'plaiceholder' 22 23// ローカルの代替アイキャッチ画像 24import { eyecatchLocal } from 'lib/constants' 25 26export default function Post({ 27 title, 28 publish, 29 content, 30 eyecatch, 31 categories, 32 tags, 33 description, 34 prevPost, 35 nextPost, 36}) { 37 useEffect(() => { 38 // scriptを読み込み 39 const script = document.createElement('script') 40 script.src = '//cdn.iframe.ly/embed.js' 41 document.body.appendChild(script) 42 // アンマウント時に一応scriptタグを消しておく 43 return () => { 44 document.body.removeChild(script) 45 } 46 }, []) 47 48 return ( 49 <Container> 50 <Meta 51 pageTitle={title} 52 pageDesc={description} 53 pageImg={eyecatch.url} 54 pageImgW={eyecatch.width} 55 pageImgH={eyecatch.height} 56 /> 57 58 <article> 59 <PostHeader title={title} subtitle="Blog Article" publish={publish} /> 60 61 <figure> 62 <Image 63 key={eyecatch.url} 64 src={eyecatch.url} 65 alt="" 66 layout="responsive" 67 width={eyecatch.width} 68 height={eyecatch.height} 69 sizes="(min-width: 1152px) 1152px, 100vw" 70 priority 71 placeholder="blur" 72 blurDataURL={eyecatch.blurDataURL} 73 /> 74 </figure> 75 76 <TwoColumn> 77 <TwoColumnMain> 78 <PostBody> 79 <ConvertBody contentHTML={content} /> 80 </PostBody> 81 <div className="sptbOnly share"> 82 <Share /> 83 </div> 84 </TwoColumnMain> 85 <TwoColumnSidebar> 86 <div className="sptbOnly pagerWrap"> 87 <Pagination 88 prevText={prevPost.title} 89 prevUrl={`/blog/${prevPost.slug}`} 90 nextText={nextPost.title} 91 nextUrl={`/blog/${nextPost.slug}`} 92 /> 93 </div> 94 <PostCategories categories={categories} /> 95 <PostTags tags={tags} /> 96 <div className="pcOnly sharebtnWrap"> 97 <Share /> 98 </div> 99 </TwoColumnSidebar> 100 </TwoColumn> 101 102 <div className="pcOnly pagerWrap"> 103 <Pagination 104 prevText={prevPost.title} 105 prevUrl={`/blog/${prevPost.slug}`} 106 nextText={nextPost.title} 107 nextUrl={`/blog/${nextPost.slug}`} 108 /> 109 </div> 110 </article> 111 </Container> 112 ) 113} 114 115export async function getStaticPaths() { 116 const allSlugs = await getAllSlugs() 117 118 return { 119 paths: allSlugs.map(({ slug }) => `/blog/${slug}`), 120 fallback: false, 121 } 122} 123 124export async function getStaticProps(context) { 125 const slug = context.params.slug 126 127 const post = await getPostBySlug(slug) 128 129 const description = extractText(post.content) 130 131 const eyecatch = post.eyecatch ?? eyecatchLocal 132 133 const { base64 } = await getPlaiceholder(eyecatch.url) 134 eyecatch.blurDataURL = base64 135 136 const allSlugs = await getAllSlugs() 137 const [prevPost, nextPost] = prevNextPost(allSlugs, slug) 138 139 return { 140 props: { 141 title: post.title, 142 publish: post.publishDate, 143 content: post.content, 144 eyecatch: eyecatch, 145 categories: post.categories, 146 tags: post.tags, 147 description: description, 148 prevPost: prevPost, 149 nextPost: nextPost, 150 }, 151 } 152} 153

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

Twitter widgetの読み込みのタイミングが悪いのかと考え、もともとcompenets/meta.js内に記述していた<script async src="https://platform.twitter.com/widgets.js"></script>をdocument.js内の<Head> ~ </Head>内に記述を移動した
→検証環境での不安定さに変化なし


補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

[slug],js内に以下の記述を行っていた
useEffect(() => {
twttr.widgets.load()
}, [richText])

これを、components/covert-body.jsに書くことで解決

投稿2024/05/28 17:01

alolo

総合スコア9

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問