こんにちは、”はふぃ”です。

Vue.jsアプリケーションのNuxt.jsで使われるinjectという処理をご存知でしょうか?

injectはプラグインとして利用するのですが、その名の通り処理を注入するという意味です。

inject関数を利用して処理を注入することで、その処理をVueインスタンスやstoreなどで先頭に $ をつけることで簡単に呼び出せるようになります!

injectを使った処理の例

例えば、cookieの値を取得する処理をinject関数を使って書くと以下のようになります。

< plugins/cookie.js >

export default function injectCookie (context, inject) {
  const getCookieVal = key => {
    const foundVal = document.cookie
      .split(';')
      .map(str => str.replace(/^\s+/, ''))
      .map(str => str.split('='))
      .find(([k, v]) => k === key)
    return foundVal &amp;&amp; foundVal[1]
  }

  inject('cookie', { get: getCookieVal })
}

getCookieVal()がcookieから任意のkeyの値を取得するメソッドでそれをcookieのget()に注入しています。

このファイルをnuxt.config.jsに設定します。

< nuxt.config.js >

plugins: [
  { src: '~/plugins/cookie', ssr: false }
],

このプラグインをFormに入力した値をCookieにセットし、次の画面読み込みでその値を取得して画面に表示するVueアプリケーションで利用すると以下のようになります。

< components/pages/sample/InjectInInjectPage/index.vue >

<template>
  <div>
    <div>Cookieの値:{{ cookieVal }}</div>
    <div>
      <input v-model="inputVal">
      <button @click="onClickBtn">Cookieに保存</button>
    </div>
  </div>
</template>

<script>
const COOKIE_KEY = 'InjectInInjectPage'

export default {
  data () {
    return {
      cookieVal: '', // Cookieから取得した値
      inputVal: '' // Formに入力された値
    }
  },
  beforeMount () {
    // Cookieから値を取得
    this.cookieVal = this.$cookie.get(COOKIE_KEY)
  },
  methods: {
    onClickBtn () {
      // Formの値をCookieに保存
      document.cookie = `${COOKIE_KEY}=${this.inputVal};path=/;max-age=180`
    }
  }
}
</script>

ハイライトが当たっているところを見るとわかるように、this.$cookie.get()で先ほどinjectした処理を呼び出しています。

実際にブラウザで動作確認をすると…

まずFormにCookieにセットする値を入力し、ボタンをクリックします。

するとCookieに保存されます。

その状態で画面をリロードするとthis.$cookie.get()が呼ばれて、先ほどセットした値が表示されます。

このようにinject関数を使うことで処理を共通化し、今回のようなVueアプリケーションだけでなく、storeやサーバーサイドでも利用することができるようになるので非常に便利です!

injectの中でinjectした処理を呼ぶ方法

injectに設定された処理は複数箇所で利用されることを前提としていることが多いので、別のinject関数内でも利用したくなることがあると思います。

例えば、文字列を大文字に変換する処理を注入するinject関数があったとします。(本来こんな単純な処理はinjectしませんが…)

< plugins/uppercase.js >

export default function injectUppercase (context, inject) {
  const uppercaseFunc = str => typeof str === 'string' ? str.toUpperCase() : str

  inject('uppercase', { convert: uppercaseFunc })
}

このメソッド内で先ほどのcookieの処理を呼び出し、最終的にcookieから取得した値を大文字化して返すinject関数とするにはどうしたらよいでしょう?

間違った方法

Vueアプリケーションと同様、先頭に $ をつけて呼ぶことをまず考えると思いますが、これでは動作しません。

< plugins/uppercase.js >

const COOKIE_KEY = 'InjectInInjectPage'

export default function injecUppercase (context, inject) {
  const uppercaseFunc = () => {
    const str = this.$cookie.get(COOKIE_KEY)
    return typeof str === 'string' ? str.toUpperCase() : str
  }

  inject('uppercase', { convert: uppercaseFunc })
}

正しい方法

このような場合はthisの代わりにcontext.appを利用します。

const COOKIE_KEY = 'InjectInInjectPage'

export default function injecUppercase (context, inject) {
  const uppercaseFunc = () => {
    const str = context.app.$cookie.get(COOKIE_KEY)
    return typeof str === 'string' ? str.toUpperCase() : str
  }

  inject('uppercase', { convert: uppercaseFunc })
}

このように記述することで、以下のようにVueアプリケーションの方でthis.$uppercase.convert()を呼ぶだけで$cookie.get()の処理も内部的に呼び出され、処理を行うことが可能となります。

< components/pages/sample/InjectInInjectPage/index.vue >

<template>
  <div>
    <div>Cookieの値:{{ cookieVal }}</div>
    <div>
      <input v-model="inputVal">
      <button @click="onClickBtn">Cookieに保存</button>
    </div>
  </div>
</template>

<script>
const COOKIE_KEY = 'InjectInInjectPage'

export default {
  data () {
    return {
      cookieVal: '', // Cookieから取得した値
      inputVal: '' // Formに入力された値
    }
  },
  beforeMount () {
    // Cookieから値を取得
    this.cookieVal = this.$uppercase.convert()
  },
  methods: {
    onClickBtn () {
      // Formの値をCookieに保存
      document.cookie = `${COOKIE_KEY}=${this.inputVal};path=/;max-age=180`
    }
  }
}
</script>

まとめ

この内容はNuxt.jsの公式ドキュメントにも載っているのですが、探しづらかったので記事にしました。

統合された注入

参考:https://ja.nuxtjs.org/guide/plugins/

参考

今回のコードはgithubで公開中なので参考にしてみてください!↓

https://github.com/hafilog/vue-sample/tree/master/components/pages/sample

投稿者: はふぃ

若手のWEBフロントエンジニア。最近はバレーボールにハマってます!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA