[Nuxt.js]Pay.jpの「既にインスタンス化されています」というエラーを解決する

コード Vue.js/Nuxt.js

Nuxt.jsで作っているサイトに決済サービスのPay.jpを導入しようとした際に「既にインスタンス化されています」というエラーが発生したので対処法をまとめます。

エラーの発生条件

次のような流れで決済画面にアクセスするとエラーが発生します。

1.決済画面とは別のページにアクセス

2.決済画面に非同期で遷移

3.決済画面から別のページに非同期で遷移 or ブラウザバック

4.決済画面に非同期で遷移(2回目)←ここでエラーが発生します。

非同期で遷移したときのみ発生しaタグでの遷移やリロードでは発生しません。

決済画面へのリンクをrouter-linkやnuxt-linkではなくaタグで設置する方法もありますが、せっかくNuxt.jsを使うので今回は非同期で遷移してもエラーが発生しないように実装します。

決済フォームを作成

まずはドキュメント通りにコードを書きます。
HTML
(デザインの都合でカード番号・有効期限・CVCで分けています)

<div id="number-form"></div>
  </div>
  <div id="expiry-form" class="payjs-outer">
  </div>
  <div id="cvc-form" class="payjs-outer">
  </div>
  <br>
  <input type="submit" @click="change" style="width:300px;">更新</div>

JavaScript

export default {
    data() {
        return {
            numberElement: null,
            elements:null,
        }
    },
    mounted() {
        this.$nextTick(function() {
            var payjp = Payjp('公開鍵')
            var elements = var elements4 = payjp.elements()
            this.elements = elements
            this.numberElement = elements.create('cardNumber');
            var expiryElement = elements.create('cardExpiry');
            var cvcElement = elements.create('cardCvc');
            this.numberElement.mount("#number-form")
            expiryElement.mount("#expiry-form")
            cvcElement.mount("#cvc-form")
        })
    },
    methods: {
        change: function() {
            this.elements.createToken(this.numberElement).then(function(r) {
                console.log(r)
            })
        },
    },
}

このコードでボタンをクリックするとコンソールにトークンが出力されます。

エラーを解決する

上のコードで発生するエラーを解決していきます。

このエラーは一度オブジェクトを生成した状態で再度オブジェクトを生成しようとして発生しています。

リロードすると過去に生成されたオブジェクトはリセットされるのでエラーが発生せず非同期で遷移するとオブジェクトがリセットされないためエラーが発生します。

今回はこれを解決するためにVuexを使います。

この記事ではNuxt.jsを使っています確認していませんがVue.jsでも同じことができると思います。

store/pay.js

export const state = () => ({
    payjp:null
});

export const mutations = {
    add(state, payjp) {
      state.payjp = payjp("公開鍵")
    },
}

JavaScript

export default {
    data() {
        return {
            numberElement: null,
        }
    },
    mounted() {
        this.$nextTick(function() {
            if (this.$store.state.pay.payjp == null) {
                this.$store.commit('pay/add', Payjp)
            }
            var elements = this.$store.state.pay.payjp.elements()
            this.numberElement = elements.create('cardNumber',);
            var expiryElement = elements.create('cardExpiry');
            var cvcElement = elements.create('cardCvc');
            this.numberElement.mount("#number-form")
            expiryElement.mount("#expiry-form")
            cvcElement.mount("#cvc-form")
        })
    },
    methods: {
        change: function() {
            this.$store.state.pay.payjp.createToken(this.numberElement).then(function(r) {
                console.log(r)
            })
        },
    },
}

PayjpのオブジェクトをVuexに一度だけ保存するように書くことでエラーが消えました。

if (this.$store.state.pay.payjp == null) {
  this.$store.commit('pay/add', Payjp)
}

この部分で既に生成されているのか一回目なのかを判定しています。

参考リンク

PAY.JP
支払いをもっとシンプルに。PAY.JPならシンプルなAPI・多彩な機能・分かりやすい料金形態のもと、WEB・モバイル・IoTなど様々なシーンで決済を導入する事が可能です。
Vue.jsについての基礎(Nuxt.jsでのVuex) - Qiita
はじめにおはようございます。こんにちは。こんばんは。 Watatakuです。 今回は以前こちらで書かせていただいた内容の中で「次回Vuexやるよー」と言っておきながらやっていなかったのでやっていきます。Vuexとは...

コメント

タイトルとURLをコピーしました