Nuxt.js(Vue) APIで取得した画像やデータで動的にOGP設定を変える方法

Nuxt.js(Vue)でOGP設定をAPIで取得した画像やデータで、ページごとに動的に変えたい時の方法です。

一般的なNuxt.jsでのOGP設定については、下記の記事にまとめています。

[【Nuxt.jsでOGP設定をする方法】](https://qiita.com/To-K/items/317a02620fe3f5b92673)

## mountedではmetaタグは書き換えられるけどOGPのクロールボットは読みにこれない
下記のように、mounted()でAPIを取得して、OGPを動的に書き換えようとしても上手く行きませんでした。

```vue:
<script lang="ts">
import Vue from 'vue'
import axios from 'axios'

export default Vue.extend({
  data() {
    return {
      userId: 0,
      profilePicture: '',
      comment: '',
    }
  },
  mounted() {
    this.profileGet()
  },
  methods: {
    async profileGet(): Promise<void> {
      const response = await axios
        .get('/api/profile/search', {
          params: {
            id: this.$route.params.id
          }
        })
        .catch((error) => error.response)
      if (
        response.data.status !== 'success' ||
        response.data.data.data.length <= 0
      ) {
        this.$router.push('/')
      }
      this.setData(response.data.data.data[0])
    }
  },
  head() {
    return {
      meta: [
        {
          hid: 'og:description',
          property: 'og:description',
          content: this.comment
        },
        {
          hid: 'og:url',
          property: 'og:url',
          content: this.snsUrl
        },
        {
          hid: 'og:image',
          property: 'og:image',
          content: this.profilePicture
        }
      ]
    }
  }
})
</script>

```
metaタグ自体はしっかりと書き換わるのですが、OGPをクロールするボットはクライアント側の処理を汲み取ってくれないようです。その為、twitterなどでシェアしようとしても画像は表示されません。

mountedのライフサイクルのタイミングはDOMが作成された直後の状態です。画面表示の為のAPI取得では問題ないですが、OGPを動的に変える場合は他のライフサイクルを使う必要があります。


## asyncDataでapiを取得することで解決

Nuxt.jsにはasyncDataメソッドがあり、サーバーサイドレンダリングすることができます。

`asyncData はコンポーネントがロードされる前に毎回呼び出されます。サーバーサイドレンダリングや、ユーザーがページを遷移する前にも呼び出されます。`
下記の公式サイトに詳しく説明が載っています。

[asyncData メソッド](https://ja.nuxtjs.org/api/)

moutendからasyncDataにAPIの取得タイミングを変更しました。

```vue

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  async asyncData(context: any) {
    try {
      const response = await context.$axios
        .get('/api/profile/search', {
          params: {
            param: context.params.id
          }
        })
        .catch((error: any) => error.response)

      if (
        response.data.status !== 'success' ||
        response.data.data.data.length <= 0
      ) {
        context.redirect('/top')
      }

      return {
        userId: Number(context.params.id),
        profilePicture: String(response.data.data.data[0].profilePicture),
        comment: String(response.data.data.data[0].comment)
      }
    } catch (error) {
      return {
        userId: 0,
        profilePicture: '',
        comment: ''
      }
    }
  },
  head() {
    return {
      meta: [
        {
          hid: 'og:description',
          property: 'og:description',
          content: this.comment
        },
        {
          hid: 'og:url',
          property: 'og:url',
          content: this.snsUrl
        },
        {
          hid: 'og:image',
          property: 'og:image',
          content: this.profilePicture
        }
      ]
    }
  }
})
</script>
```

asyncDataメソッドでapiを取得することで、OGPも動的に書き換えることができました。
ユーザー情報やブログの記事のようにページごとにOGPを変化させたい時は、asyncDataを使うのがベストかなと思います。

＊asyncData（）はページコンポーネントのみで使用できます。子コンポーネントでは使用できない点には注意が必要です。