yasutomogのブログ

Software Engineerの雑記

Nuxt.jsでPAY.JPの初期化エラー(既にインスタンス化されています)対策

概要

  • Nuxt.jsベースでJamstackなECサイトのサンプル実装しているときに、PAY.JPの初期化でエラーが出ることがあったのでメモ
  • PAY.JPを実装するにあたり、payjp(2.0.5)のnode moduleを利用
  • 画面側ではpayjpCardElementを生成し、トークンを作成して決済用のAPI呼び出す流れで実装

エラーとなる実装

<template>
  <div id="payjp-form"></div>
</template>
<script>
  mounted() {
    const payjp = window.Payjp(process.env.PAY_JP_PK)
    const elements = this.payjp.elements()
    const cardElement = elements.create('card')
    cardElement.mount('#payjp-form')
    cardElement.on('change', async (event) => {
      if (event.complete) {
        const res = await this.$payjp.createToken(cardElement)
        this.payjpToken = res.id
        this.isValidCard = true
      }
    })
  },
</script>
  • 画面初期表示時は問題なくカードレイアウトが表示されていたが、画面遷移後、再び画面を開くと「Error: 既にインスタンス化されています」というエラーが発生。
    複数回の初期化処理はNGとのこと。

対応策(Pluginを作成し初期化を1度に制御する)

  • plugins/payjp.jsを新規作成
import Vue from 'vue';

export default ({store, isHMR}) => {

  if (isHMR) return

  if (process.client) {

    Vue.prototype.$payjp = window.Payjp(process.env.PAY_JP_PK)
  }
}
  • nuxt.config.jsにPlugin定義追加
plugins: [
  '~/plugins/payjp.js',
],
  • エラーとなっていた画面の修正
<template>
  <div id="payjp-form"></div>
</template>
<script>
  mounted() {
    const elements = this.$payjp.elements()
    const cardElement = elements.create('card')
    cardElement.mount('#payjp-form')
    cardElement.on('change', async (event) => {
      if (event.complete) {
        const res = await this.$payjp.createToken(cardElement)
        this.payjpToken = res.id
        this.isValidCard = true
      }
    })
  },
</script>