Vue.jsで困った時に見るTips

Vue.js 2018年9月2日

どうも、Vue.js愛好家です。

jQuery, Knockout, Ember, Angular, React, Riotあたりは軽く触ってきた僕が、Vueに行き着いたのは神が与え給うた運命なわけですが、今回はそんなVueでちょっと複雑なことをしようとした時に見ると助かるTipsをご紹介します。





1. computedをアロー関数で記述

めちゃくちゃ使うcomputedですが、一般的には以下のような記法です。(あえて冗長な例を書きます

computed: {
  userId() { // 三行も書かなくてはいけない
    return this.user.id
  },
  userName() {
    return this.user.name
  },
  userImage() {
    return this.user.image
  },
  ...
}

これ、コンポーネントによってはめちゃくちゃ多くて、行数が増えちゃいます。

実は、こうも書けます。

computed: {
  userId:    vm => vm.user.id, // 一行で済む!
  userName:  vm => vm.user.name,
  userImage: vm => vm.user.image,
  ...
}

はい、スッキリしましたね。アロー関数の引数にはVMコンテキスト(this)が渡るので、こういう風に書けます。

更に応用すると、こんなこともできます。

computed: {
  userPath: ({$route, user}) => `${$route.path}/${user.id}`
  ...
}

thisの中身を展開できるので、呼び出しの階層を一段階下げられます。ちなみに、Nuxt.jsでは動きません(笑)

2. refコンポーネントのイベントをtemplate内で呼び出す

Modalコンポーネントを呼び出せるようなページを、以下のように作ります。

<template>
  <div id="home">
    <h1>Home Page</h1>
    <button @click="$refs.modal.open">モーダルを開く</button>
    
    <modal ref="modal"/> <!-- 自分で作ってネ -->
  </div>
</template>

これはエラーが出ます。$refs.modalが解決できるのはmounted後なので、それ以前では$refs.modal.openを解決できないためです。

そのため、通常はmethodsopenModal関数を書いて、それを@clickで呼び出すことが多いです。

@click="openModal"

...

methods: {
  openModal() {
    this.$refs.modal.open()
  }
}

しかし、@click.stopを使用すると、メソッドを経由せずに書くことができます。

<template>
  <div id="home">
    <h1>Home Page</h1>
    <!-- stopを付けるだけ -->
    <button @click.stop="$refs.modal.open">モーダルを開く</button>
    
    <modal ref="modal"/>
  </div>
</template>

まさにハック!笑

3. ネストしたプロパティをwatch

文字列でおk

  watch: {
    '$route.params.userId'(newId, oldId) {
      ここに処理を書く
      ...
    },
    // メソッドも呼び出せる
    '$route.query.page': 'onChangePage'
  }

4. グローバルイベントの登録

全コンポーネントに共通したイベントを登録したい場合、大きく2つの方法があります。

store#actionsで登録

これが一番簡単です。this.$store.dispatch('action', params)で呼び出せるようにする方法です。(ref. アクション)

ただ、これは$store.stateをいじるとき以外はあまり使いたくありません。

eventbusで登録

これはグローバルイベントを登録する用のモデルを用意して、そいつを経由してイベントを発火する方法です。(ref. Creating a Global Event Bus with Vue.js

まず、プロジェクトルートに以下を作成します。

import Vue from 'vue'
export const EventBus = new Vue()

そして、グローバルイベントを登録するタイミングは、以下のようにcreated内に$onを用いて記述します。

<template>
  <div id="home">
    <h1>Home Page</h1>
    <button @click="openModal('Hello Modal!')">モーダルを開く</button>
    
    <modal ref="modal" @close="closeModal"/>
  </div>
</template>

<script>
  import EventBus from '@/eventbus.js

  export default {
    created() {
      EventBus.$on('open-global-modal', this.openModal)
      EventBus.$on('close-global-modal', this.closeModal)
    },
    // コンポーネントのdestroyedのタイミングで登録を解除したい場合は、このように書く
    destroyed() {
      EventBus.$off('open-global-modal', this.openModal)
      EventBus.$off('close-global-modal', this.closeModal)
    },
    methods: {
      openModal(message) {
        this.$refs.modal.open(message)
      },
      closeModal() {
        this.$refs.modal.close()
      }
    }
  }
</script>

あとは、他のコンポーネントから同じくEventBus経由で$emitを呼ぶだけです。

<template>
  <div id="other">
    <h1>Other Page</h1>
    <button @click="openModal('Hello Modal!')">モーダルを開く</button>
  </div>
</template>

<script>
  import EventBus from '@/eventbus.js

  export default {
    methods: {
      openModal(message) {
        EventBus.$emit('open-global-modal', message)
      }
    }
  }
</script>

イベントの登録管理が面倒ですが、便利な場面が多々あるので、覚えていて損はないです。

5. 【非推奨】setTimeoutでレンダリングハック

もうなんだか構造が複雑過ぎて、レンダリング周りで思った挙動にならない!表示されない!だけどバグ報告が上がって、とりあえず直さなきゃ!

そんな時は、

setTimeout(() => {
  ...ここに処理を書く
}, 0)

Vueのライフサイクルを全無視した処理なので、全くおすすめしないですが、これで、なんとかなることは多いです(笑)。が、本当に緊急対応などでのみ使いましょう。

おわりに

僕が実装していてそこそこ使っているものを紹介しましたが、いかがでしょうか?他にも面白いTipsがあれば教えてください!

slont

金融ベンチャーでWebエンジニア

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.