結論

重複を避けたいタグに key オプションを追加し、同名のキーを設定します。

import Head from 'next/head'

function IndexPage() {
  return (
    <div>
      <Head>
        <title>My page title</title>
        <meta property="og:title" content="My page title" key="title" />
      </Head>
      <Head>
        <meta property="og:title" content="My new title" key="title" />
      </Head>
      <p>Hello world!</p>
    </div>
  )
}

export default IndexPage

こちらのコードの場合、重複しているmetaタグのうち後者のみがレンダリングされます。

next/headDedupe only items with unique key #5800

背景

当ブログは、ブログに関する情報は pages/_app.tsx のHeadタグ内に、ブログ記事ごとの情報は lib/components/layout.tsx のHeadタグ内にメタ情報として設定してあります。しかし、上記で示したようなmetaタグの key オプションが設定されていなかったため、og:title 等のOGPに関するmetaタグが重複したままparseされてしまい、例えばSlackチャンネルにブログ記事のリンクを貼り付けた際に、各記事のタイトル等のメタ情報が表示されませんでした。


その他の方法

nfl / react-helmet

こちらのreact-helmetというライブラリを使っても解決できそうです。

Headタグ内のmetaタグが重複した場合、ネストしている子コンポーネントのタグをparseします。

使い方も簡単で、

import React from "react";
import {Helmet} from "react-helmet";

class Application extends React.Component {
  render () {
    return (
        <div className="application">
            <Helmet>
                <meta charSet="utf-8" />
                <title>My Title</title>
                <link rel="canonical" href="http://mysite.com/example" />
            </Helmet>
            ...
        </div>
    );
  }
};

このように対象のタグを <Helmet> で囲むだけで対応してくれます。

ただ、Nextプロジェクトで試してみたところ、

Unhandled Runtime Error
TypeError: Cannot read property 'tagName' of null

エラーが発生してしまいビルドできなかったです。

react-helmet example

Next.jsの場合はこちらのサンプルリポジトリを参考にすると実現できそうです💪

とはいえ、Next.jsの場合は最初のやり方で対処してくれるので、 react-helmet を使う必要はなさそうです。


さいごに

今回の件でドキュメントの重要性を再確認できました。Next.jsの場合ドキュメントは英語ではありますが、フレームワーク自体がシンプルなのでドキュメントも読みやすいです。なので、毛嫌いせずに読み込んでみます。

OpenGraphに関しては、以下のサイトでURLを入力することでプロパティ設定を調べることができます。

Facebook for Developers / シェアデバッガー

修正が必要な箇所や、SNSにURLを投稿した際のプレビューなども確認することができます。