Vueミックスイン と Vueコンポーネントの併用で気をつけるべきこと

こんにちは!フリーランス・エンジニアの 九保すこひ です。

さてさて、ちょっと今の開発が多忙でブログ記事をお休みしてしまいましたが、おかげでいくつか公開したい内容が見つかりました。そのため、また「好きだからやってる」ぐらいのゆるいスタンスで更新をしていこうと考えています😊

そして、今回の内容は私が実際に遭遇して「あ、しまった💦」となった体験が元になっているので、ぜひ皆さんも気をつけてください。

具体的にはというと・・・

VueミックスインとVueコンポーネントを併用するときは注意が必要!

ということです。

それでは、順を追ってご紹介していきます。
ぜひ皆さんのお役に立てると嬉しいです😊✨

開発環境: Vue 2.6

何が問題となったか

まず私が遭遇して「あ・・・」となった現象を紹介します。

まず、サイトに共通で表示する情報(サイドバーの新着情報など)をAjaxで取得するようにしていました。

そして、いつものごとくVueコンポーネントで「使い回し」ができる開発を進めていると、ある出来事に気が付きました。

それは、

何度も同じAjax通信が発生

していたことです。

こんな感じです↓↓↓

もちろん、URLもパラメーターも全く同じなので、「いや、1回でいいでしょ😅」となってしまいました。

何をどうしていたのか

では、こんな状態になった状況はどんなものだったのかをご説明します。

Vueコンポーネントをつくった

まず、以下のようなコンポーネントをつくりました。

/js/vue/components/test.js

Vue.component('v-test', {
    template: 'テストコンポーネント'
});

Vueミックスインもつくりました

Vueミックスイン」とは、特定情報にどこからでもアクセスできる機能のことで、例えば、「数字を3桁カンマ区切りにする関数」などは便利なので、よくミックスインの中に入れておいたりします。

そして、冒頭でも書いたように全ページで必要なデータを以下のように取得していました。

Vue.mixin({
    mounted() {

        // 全ページに必要なデータを取得
        axios.get('/api_app');

    }
});

VueミックスインとVueコンポーネントを使ってページを作成した

そして、意気揚々とここまでで作ったVueミックスインとVueコンポーネントを併用するページをつくりました。

<html>
<body>
    <div id="app">

        <v-test></v-test>
        <v-test></v-test>
        <v-test></v-test>
        <v-test></v-test>
        <v-test></v-test>

    </div>
    <!-- ライブラリ -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <!-- Vueコンポーネント、ミックスイン -->
    <script src="/js/vue/mixins/app.js"></script>
    <script src="/js/vue/components/test.js"></script>
    <script>

        new Vue({
            el: '#app'
        });

    </script>
</body>
</html>

しかし!

このコードのせいで、さっきの「いや、1回でいいでしょ😅」が引き起こされることになってしまったのです。

何が問題だったのか

では、何か問題だったのでしょうか。
原因としては、

Vueミックスインをグローバルに設定してしまったから

です。

※ここで言う「グローバル」とは、英語を使うことや国際感覚をもつという意味ではなく、「どこからでもアクセスできる」という意味です。

つまり、結論からいうと以下のようにミックスインを作ると、

Vue.mixin({

    // 省略

});

全Vueコンポーネントでこのミックスインが有効になる

のです。

つまり、今回の例で言うと、コンポーネント5つ分のAjax通信が発生してしまったんです。

では、どのようにすればいいか

解決策として2つご紹介しますが、簡単に言うと、

  1. ひとつずつ必要な場所で設定する方法
  2. 一気に設定する方法

になります。

ひとつずつ見ていきましょう!

ひとつずつ必要な場所で設定する方法

1つ目は、よく解決策として使われる「ミックスインをローカルで使う」方法です。(グローバルの逆ですね)

やりかたは、まずVue.mixin()を使わず単なるオブジェクトとして設定をします。

/js/vue/mixins/app.js

const appMixin = {
    mounted() {

        axios.get('/api_app');

    }
};

そして、使いたい場所でミックスインを設定します。

<script src="/js/vue/mixins/app.js"></script>
<script src="/js/vue/components/test.js"></script>
<script>

    new Vue({
        el: '#app',
        mixins: [appMixin]
    });

</script>

もちろん、コンポーネントでも以下のようにすることでミックスインを使うことができます。

Vue.component('v-test', {
    template: 'テストコンポーネント',
    mixins: [appMixin]
});

なお、webpackなどでコンパイルして使う場合は、次のようにすることで対応できます。

window.appMixin = {

    // 省略

};

ただし・・・

このミックスインを「ローカル」として個別に設定する場合は、ちょっと面倒だったりするのも事実です。

そのため、次は一気に設定する方法をご紹介します。

一気に設定する方法

やり方としては、一番最初のVue.mixin()を使ったグローバルな使い方の応用バージョンです。

結論としては以下のコードを使います。

Vue.mixin({
    mounted() {

        if(this.$el.id === 'app') {

            // 全ページに必要なデータを取得
            axios.get('/api_app');

        }

    }
});

$elは、Vueインスタンスが対象にしている要素のことなので、このidをチェックしてVue本体かどうか判別しています。(idは、重複することがないことを利用しています)

つまり、このidは、Vueelの部分と一致しないといけません。

new Vue({
    el: '#app'
});

なお、元々は以下のようにクラス名を取得して判断していましたが、この方法だとVueインスタンスを2つ作った場合は対応できませんし、なによりwebpackでコンパイルするとクラス名が変更になってしまうのでうまくいきません。

// 【注意】これはおすすめしない方法です。

Vue.mixin({
    mounted() {

        if(this.constructor.name === 'Vue') {

            // 省略

        }

    }
});

おわりに

ということで、今回はVueミックスインとVueコンポーネントを併用するときに気をつけておくべきことをご紹介しました。

この部分は、ページの速度にも関わってきますので、ぜひテクニックとして活用していただきたいです。

ちなみに、少しテーマから外れますが今回の記事をチェックしていて、「あー、もう完全にES6ばかり使ってるな」と実感しました。

やっぱりコードが少なくていいのは、めんどくさがり屋にとって「ビールを飲んでるときの唐揚げ」のように魅力的です。(お酒を飲まれない方はスルーしてください😅)

ではでは〜!

この記事が役立ちましたらシェアお願いします😊✨ by 九保すこひ
また、わかりにくい部分がありましたらお問い合わせからお気軽にご連絡ください。
このエントリーをはてなブックマークに追加       follow us in feedly