DATA-WORLD-BLOG

Next.js/ReactでInstagramの埋め込み

👤horomi

概要

このドキュメントは、Instagramの埋(う)め込(こ)みコードをNext.jsで使用(しよう)する方法について説(せつ)明(めい)しています。また、Reactコンポーネントをクライアントサイドでレンダリングする方法についても説明(せつめい)しています。最後(さいご)に、ESLintのエラーに対(たい)する解決策(かいけつさく)についても説明(せつめい)しています。


以下、ChatGPT

❓ Prompt

Nextjsで作(つく)っているブログにInstagramの埋(う)め込(こ)みをできるようにしたい

💬 Answer

Instagramの埋(う)め込(こ)みをNext.jsのブログに追加(ついか)する方法(ほうほう)は、以下(いか)の手順(てじゅん)に従(したが)って行(おこな)うことができます。

  1. npmパッケージのreact-instagram-embedをインストールします。
    npm install react-instagram-embed
    
  2. ブログのページにreact-instagram-embedをインポートします。
    import InstagramEmbed from 'react-instagram-embed'
    
  3. 埋(う)め込(こ)みたいInstagramのURLをInstagramEmbedコンポーネントに渡(わた)します。
    <InstagramEmbed
      url='<https://www.instagram.com/p/B9ZoTQ2jSSS/>'
    />
    
  4. InstagramEmbedコンポーネントにオプションを追加(ついか)することもできます。たとえば、maxWidthプロパティを設定(してい)して、埋(う)め込(こ)みの最大(さいだい)幅(はば)を指定(してい)することができます。
    <InstagramEmbed
      url='<https://www.instagram.com/p/B9ZoTQ2jSSS/>'
      maxWidth={500}
    />
    

以上(いじょう)の手順で、Next.jsのブログにInstagramの埋め込みを追加することができます。

❓ Prompt

アクセストークンなしで自分(じぶん)以外(いがい)のInstagramの投稿(とうこう)をブログに埋(う)め込(こ)むことは可能(かのう)ですか?

💬 Answer

残念(ざんねん)ながら、アクセストークンなしで自分(じぶん)以外(いがい)のInstagramの投稿(とうこう)をブログに埋(う)め込(こ)むことはできません。Instagramは、APIによるデータの取得(しゅとく)にアクセストークンを必要(ひつよう)としています。アクセストークンは、APIにアクセスするために必要(ひつよう)な認証情報(にんしょうじょうほう)の1つであり、Instagramがユーザーのプライバシーを保護(ほご)するために導入(どうにゅう)されています。

したがって、他(ほか)のユーザーのInstagramの投稿(とうこう)をブログに埋(う)め込(こ)むためには、そのユーザーが自分(じぶん)のアカウントでアクセストークンを生成(せいせい)して、そのアクセストークンを使用(しよう)してAPIからデータを取得(しゅとく)する必要(ひつよう)があります。

ただし、Instagramの公式(こうしき)ウェブサイトで提供(ていきょう)されている埋(う)め込(こ)み機能(きのう)を使用(しよう)すれば、アクセストークンなしでInstagramの投稿(とうこう)をブログに埋(う)め込(こ)むことができます。この場合(ばあい)、埋(う)め込(こ)み機能(きのう)を使用(しよう)するための埋(う)め込(こ)みコードが提供(ていきょう)されます。ただし、この方法(ほうほう)では、埋(う)め込(こ)み機能(きのう)に制限(せいげん)があることに注意(ちゅうい)してください。例(たと)えば、投稿()の詳細(しょうさい)な情報(じょうほう)を取得(しゅとく)したり、カスタマイズした埋め込みを作成(さくせい)したりすることはできません。

❓ Prompt

アクセストークンなしでInstagramの投稿(とうこう)をブログに埋(う)め込(こ)めることについて詳(くわ)しく知(し)りたいです。公式(こうしき)URLを教(おし)えて

💬 Answer

Instagramの公式(こうしき)ウェブサイトで提供(ていきょう)されている埋(う)め込(こ)み機能(きのう)を使用(しよう)すると、アクセストークンなしでInstagramの投稿(とうこう)をブログに埋(う)め込(こ)むことができます。この方法では、埋(う)め込(こ)み機能(きのう)を使用(しよう)するための埋(う)め込(こ)みコードが提供(ていきょう)されます。ただし、この方法(ほうほう)では、埋(う)め込(こ)み機能(きのう)に制限(せいげん)があることに注意(ちゅうい)してください。例(たと)えば、投稿(とうこう)の詳細(しょうさい)な情報(じょうほう)を取得(しゅとく)したり、カスタマイズした埋(う)め込(こ)みを作成(さくせい)したりすることはできません。

以下(いか)は、Instagramの公式(こうしき)ウェブサイトで提供(ていきょう)されている埋(う)め込(こ)み機能(きのう)のURLです。

https://www.instagram.com/developer/embedding/

上記(じょうき)のURLにアクセスすると、埋(う)め込(こ)みコードを生成(せいせい)するための手順(しゅじゅん)が説明(せつめい)されています。埋(う)め込(こ)みコードを生成(せいせい)するためには、以下(いか)の手順(しゅじゅん)を実行(じっこう)する必要(ひつよう)があります。

  1. 埋(う)め込(こ)みたいInstagramの投稿を開(ひら)きます。
  2. 投稿の右上隅(みぎうわすみ)にある「…」アイコンをクリックし、メニューから「埋め込む」を選択(せんたく)します。
  3. 埋め込みコードが生成(せいせい)されます。必要(ひつよう)に応(おう)じて、表示(ひょうじ)する投稿の幅(はば)や高(たか)さを調整(ちょうせい)できます。
  4. 生成(せいせい)されたコードをコピーして、ブログのHTMLに貼(は)り付(つ)けます。

以上(いじょう)の手順(しゅじゅん)で、アクセストークンなしでInstagramの投稿(とうこう)をブログに埋(う)め込(こ)むことができます。ただし、埋(う)め込(こ)み機能(きのう)には制限(せいげん)があるため、詳細(しょうさい)な情報(じょうほう)を取得(しゅとく)したり、カスタマイズした埋(う)め込(こ)みを作成(さくせい)したりするには、APIを使用(しよう)する必要(ひつよう)があります。

❓ Prompt

https://www.instagram.com/developer/embedding/を参照(さんしょう)して、埋(う)め込(こ)みコードを取得(しゅとく)しました。このコードをそのままNext.jsに貼(は)り付(つ)けるとエラーになります。修正(しゅうせい)する場所(ばしょ)を教(おし)えて下(くだ)さい

💬 Answer

Instagramの埋込(うめこ)みコードをNext.jsに貼(は)り付(つ)けるとエラーが発生(はっせい)する可能性(かのうせい)があります。これは、Next.jsはクライアントサイドのJavaScriptをサポート(サポート)しているため、Reactコンポーネント内(ない)に直接(ちょくせつ)JavaScriptを埋(う)め込(こ)むことはできません。

代(か)わりに、Next.jsでは以下(いか)の手順(てじゅん)に従(したが)って、Instagramの埋(う)め込(こ)みコードを正常(せいじょう)に表示(ひょうじ)できるようにします。

  1. Instagramの埋(う)め込(こ)みコードを取得(しゅとく)します。
  2. Reactコンポーネントを作成(さくせい)し、その中(なか)に埋(う)め込(こ)みコードを貼(は)り付(つ)けます。
  3. コンポーネントをクライアントサイドでレンダリングします。

以下(いか)は、この手順(てじゅん)を実行(じっこう)する方法(ほうほう)の例(れい)です。

  1. Instagramの埋(う)め込(こ)みコードを取得(しゅとく)します。 Instagram Developerサイトから埋(う)め込(こ)みコードを取得(しゅとく)します。コードの例(れい)は以下(いか)のようになります。
    <blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="https://www.instagram.com/p/BxxzD5pANZG/" data-instgrm-version="13">
    <a href="https://www.instagram.com/p/BxxzD5pANZG/" target="_blank"></a>
    </blockquote>
    <script async src="//www.instagram.com/embed.js"></script>
  2. Reactコンポーネントを作成(さくせい)し、その中(なか)に埋(う)め込(こ)みコードを貼(は)り付(つ)けます。 Reactコンポーネントを作成(さくせい)し、埋(う)め込(こ)みコードをその中(なか)に貼(は)り付(つ)けます。以下(いか)は、このコードの例(れい)です。
    import React, { useEffect } from "react";
    
    const InstagramEmbed = () => {
      useEffect(() => {
        if (window.instgrm) {
          window.instgrm.Embeds.process();
        } else {
          const script = document.createElement("script");
          script.src = "//www.instagram.com/embed.js";
          script.async = true;
          script.defer = true;
          document.body.appendChild(script);
        }
      }, []);
    
      return (
        <>
          <blockquote
            class="instagram-media"
            data-instgrm-captioned
            data-instgrm-permalink="https://www.instagram.com/p/BxxzD5pANZG/"
            data-instgrm-version="13"
          >
            <a href="https://www.instagram.com/p/BxxzD5pANZG/" target="_blank"></a>
          </blockquote>
        </>
      );
    };
    
    export default InstagramEmbed;

    このコンポーネントは、useEffectフックを使用(しよう)して、Instagramの埋(う)め込(う)みJavaScriptライブラリがロードされるまで待機(たいき)します。ライブラリがロードされたら、コンポーネントは window.instgrm.Embeds.process() を呼(よ)び出(だ)して、Instagramの埋(う)め込(こ)みコードをレンダリングします。

❓ Prompt

コンポーネントをクライアントサイドでレンダリングのやり方(かた)を教(おし)えて

💬 Answer

Reactコンポーネントをクライアントサイドでレンダリングするには、次(つぎ)の手順(てじゅん)を実行(じっこう)する必要(ひつよう)があります。

  1. クライアントサイドでレンダリングしたいコンポーネントを、next/dynamic メソッドを使(つか)ってロード可能(かのう)な動的(どうてき)インポートとして指定(してい)します。
    import dynamic from 'next/dynamic'
    
    const MyComponent = dynamic(() => import('../components/MyComponent'))

    この方法(ほうほう)でコンポーネントを動的(どうてき)にインポートすると、必要(ひつよう)に応(おう)じてコンポーネントをクライアントサイドでロードし、レンダリングできます。

  2. コンポーネントをレンダリングするページで、useEffect フックを使()ってクライアントサイドでのレンダリングを処理する関数を実装します。
    import React, { useEffect, useState } from 'react'
    import dynamic from 'next/dynamic'
    
    const MyComponent = dynamic(() => import('../components/MyComponent'))
    
    function MyPage() {
      const [isClient, setIsClient] = useState(false)
    
      useEffect(() => {
        setIsClient(true)
      }, [])
    
      return (
        <>
          {isClient && <MyComponent />}
          {!isClient && <div>Loading...</div>}
        </>
      )
    }
    
    export default MyPage

    この方法(ほうほう)で、クライアントサイドでのレンダリングが実行(じっこう)され、コンポーネントがページに追加(ついか)されます。useEffect フックを使(つか)って isClient ステート変数(へんすう)を初期化(しょきか)することで、クライアントサイドでのレンダリングが行(おこ)われたかどうかを確認(かくにん)できます。初期(しょき)化(か)処理(しょり)を行(おこ)わないと、ページがサーバーサイドでレンダリングされたときに、クライアントサイドでコンポーネントが再度(さいど)レンダリングされてしまう可能性(かのうせい)があります。

以上(いじょう)の手順(てじゅん)に従(したが)うことで、Reactコンポーネントをクライアントサイドでレンダリングすることができます。

❓ Prompt

無事(ぶじ)開発(かいはつ)環境下(かんきょうか)でインスタグラムの埋(う)め込(こ)みを実装(じっそう)できました。ありがとう。

💬 Answer

どういたしまして。問題(もんだい)が解決(かいけつ)できて良(よ)かったです。何(ほ)か他(ほか)に質問(しつもん)や問題(もんだい)があれば、いつでもお知(し)らせください。お力(ちから)になれるよう最善(さいぜん)を尽(つ)くします。

❓ Prompt

./components/notion-blocks/bookmark.tsx
36:35 Error: React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. react-hooks/rules-of-hooks
38:3 Error: React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render. react-hooks/rules-of-hooks

上記(じょうき)のエラーメッセージに対(たい)して対応策(たいおうさく)を教(おし)えて下(くだ)さい

💬 Answer

このエラーメッセージは、React Hooksが正(ただ)しい順序(じゅんじょ)で呼(よ)び出(だ)されていないことを示(しめ)しています。具体的(ぐたいてき)には、useStateuseEffectが条件(じょうけん)付(つ)きで呼(よ)び出(だ)されているため、問題(もんだい)が発生(はっせい)しています。

これらのHooksは常(つね)に同(おな)じ順序(じゅんじょ)で呼(よ)び出(だ)される必要(ひつよう)があります。つまり、useStateは常(つね)にコンポーネントの先頭(せんとう)で呼(よ)び出(だ)され、useEffectは次(つぎ)に呼(よ)び出(だ)される必要(ひつよう)があります。

したがって、コンポーネント内(ない)でこれらのHooksを呼(よ)び出(だ)す前(まえ)に、条件(じょうけん)付(つ)きステートメントを移動(いどう)するか、別(べつ)の関数(かんすう)に分割(ぶんかつ)する必要(ひつよう)があります。

例(たと)えば、以下(いか)のように書(か)き換(か)えることができます。

import React, { useState, useEffect } from 'react';

const Bookmark = ({ block }: any) => {
  const [showDescription, setShowDescription] = useState(false);

  useEffect(() => {
    if (block.properties.Description.title.length > 0) {
      setShowDescription(true);
    }
  }, [block.properties.Description.title]);

  return (
    <div>
      {showDescription && (
        <div>{block.properties.Description.title[0].plain_text}</div>
      )}
      <div>
        <a href={block.properties.Link.url} target="_blank" rel="noreferrer">
          {block.properties.Title.title[0].plain_text}
        </a>
      </div>
    </div>
  );
};

export default Bookmark;

このコードでは、useStateuseEffectが常(つね)に同(おな)じ順序(じゅんじょ)で呼(よ)び出(だ)されるようになっています。

❓ Prompt

修正(しゅうせい)している途中(とちゅう)でエラーメッセージが出(で)ました。
Error: Objects are not valid as a React child (found: [object URL]). If you meant to render a collection of children, use an array instead.
対策(たいさく)を教(おし)えて下(くだ)さい

💬 Answer

このエラーは、Reactが URL オブジェクトを子要素(こようそ)として直接(ちょくせつ)レンダリングしようとしていることを示(しめ)しています。Reactは、オブジェクトを文字列(もじれつ)としてレンダリングすることはできません。

このエラーを修正(しゅうせい)するために、URLオブジェクトを文字列(もじれつ)に変換(へんかん)してから、コンポーネントに渡(わた)す必要(ひつよう)があります。具体的(ぐたいてき)には、URLオブジェクトの toString() メソッドを呼(よ)び出(だ)すことができます。

以下(いか)は例(れい)です。

const [url, setUrl] = useState<string>("");

useEffect(() => {
  if (data.url) {
    const url = new URL(data.url);
    setUrl(url.toString());
  }
}, [data.url]);

これにより、URLオブジェクトが文字列(もじれつ)に変換(へんかん)され、コンポーネントに渡(わた)されるため、エラーが解決(かいけつ)されるはずです。

❓ Prompt

無事(ぶじ)修正(しゅうせい)できました。ありがとう

💬 Answer

よかったです!何(なに)か他(ほか)に問題(もんだい)があれば遠慮(えんりょ)なくお知(し)らせください。

❓ Prompt

yarn lintで確認(かくにん)すると、もうひとつエラーが出(で)ました。
Using target="_blank" without rel="noreferrer" (which implies rel="noopener") is a security risk in older browsers
対策(たいさく)を教(おし)えて下(くだ)さい

💬 Answer

このエラーは、<a> 要素(ようそ)の target 属性(ぞくせい)に "blank" を指定(してい)するときに、rel 属性(ぞくせい)に "noopener""noreferrer" を指定(してい)することを求(もと)めています。これは、セキュリティ上(じょう)の理由(りゆう)から、古(ふる)いブラウザでは別(べつ)のウィンドウやタブで開(ひら)いたリンクが、オリジナルのページに悪意(あくい)のあるスクリプトを実行(じっこう)する可能性(かのうせい)があるためです。

修正(しゅうせい)するには、<a> 要素(ようそ)の rel 属性(ぞくせい)に "noopener""noreferrer" を追加(ついか)する必要(ひつよう)があります。

❓ Prompt

rel="noreferrer"の追加(ついか)漏(も)れが末尾(まつび)にあることを発見(はっけん)しました。無事(ぶじ)yarn lintも通過(つうか)しました!マジありがとう

💬 Answer

よかったです!何(なに)かあればいつでも聞(き)いてください。

できた\(^o^)/

InstagramのPOSTとREELを埋(う)め込(こ)めるようになりました!

少(すこ)し時間(じかん)があるときに

埋(う)め込(こ)んだ時(とき)のデザインをカスタマイズできたらいいなと思(おも)います⭐