🦁

最低限わかるVue Composition API

2021/08/05に公開

この資料について

この資料はVue2.0で動くプロダクトでVue Composition APIについて簡単に解説し、関心をもってもらうために用いた際のものです。

対象読者は以下を想定しています。

  • VueのOption API(今までの書き方)をさわったことがある
  • React Hooksの経験がない

より詳細な知識は公式ドキュメントよりご参照ください。

Vue 3系のコンポジションapi について

ってなんですか

なにがうれしいのか

  • 機能単位でカプセル化っぽくできる
  • vue独特の書式が減る(dataプロパティとか暗黙のthisとか)

いままでの書き方

※Option APIと呼ぶ

<template>
  <div>
    <h1>Counter App</h1>
    <div>{{ count }}</div>
    <button @click="increment">increment</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>

新しい書き方

Vue3.0 composition apiだと

<template>
  <div>
    <h1>Counter App</h1>
    <div>{{ state.count }}</div>
    <button @click="increment">increment</button>
  </div>
</template>

<script>
import { reactive } from 'vue'

export default {
  setup() {
    const state = reactive({ count: 0 })

    const increment = () => {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
<script>

こまかく見ていくと

step1

export default {
  setup() {
    // setupメソッドの中に処理をまとめて書く
  }
}

step2

import { reactive } from 'vue'

export default {
  setup() {
    // オブジェクトをreactiveメソッドに通す
    const state = reactive({ count: 0 })
  }
}

step3

export default {
  setup() {
    const state = reactive({ count: 0 })
    
    // 状態の更新関数をつくる
    const increment = () => {
      state.count++
    }
  }
}

step4

export default {
  setup() {
    const state = reactive({ count: 0 })

    const increment = () => {
      state.count++
    }
    
    // vue templateで使うものをreturnする
    return {
      state,
      increment
    }
  }
}

これで何が変わるの?

setup内を「ただの関数」として分離できる

import { reactive } from 'vue'

function useCounter () {
  const state = reactive({ count: 0 })

  const increment = () => {
    state.count++
  }

  return {
    state,
    increment
  }
}

export default {
  setup() {
    const { state, incremet } = useCounter()

    return {
      state, 
      incremet
    }
  }
}

くわえて

任意の処理を別の関数として分離できる

decrementを別の関数として分離してみた

<template>
  <div>
    <h1>Counter App</h1>
    <div>{{ count1.count }}</div>
    <button @click="increment">increment</button>

    <div>{{ count2.count }}</div>
    <button @click="decrement">decrement</button>
  </div>
</template>

<script>
import { reactive } from 'vue'

function useCounter () {
  const count1 = reactive({ count: 0 })

  const increment = () => {
    count1.count++
  }

  return {
    count1,
    increment
  }
}

function useCounter2 () {
  const count2 = reactive({ count: 0 })

  const decrement = () => {
    count2.count--
  }

  return {
    count2,
    decrement
  }
}

export default {
  setup() {
    return {
      ...useCounter(),
      ...useCounter2()
    }
  }
}
<script>

class構文でカプセル化するのと
なんか似てる

これができると

機能単位で独立したモジュールが作れる

useCounter.js というファイル

useCounter.js
import { reactive } from 'vue'

export function useCounter () {
  const count1 = reactive({ count: 0 })

  const increment = () => {
    count1.count++
  }

  return {
    count1,
    increment
  }
}

useCounter2.js というファイル

useCounter2.js
import { reactive } from 'vue'

export function useCounter2 () {
  const count2 = reactive({ count: 0 })

  const decrement = () => {
    count2.count--
  }

  return {
    count2,
    decrement
  }
}

Counter.vue に import するだけでカウンター機能が使える

<template>
  <div>
    <h1>Counter App</h1>
    <div>{{ count1.count }}</div>
    <button @click="increment">increment</button>

    <div>{{ count2.count }}</div>
    <button @click="decrement">decrement</button>
  </div>
</template>

<script>
import { useCounter } from '@/hooks/useCounter'
import { useCounter2 } from '@/hooks/useCounter2'

export default {
  setup() {
    const { count1, increment } = useCounter()
    const { count2, decrement } = useCounter2()

    return {
      count1,
      increment,
      count2,
      decrement
    }
  }
}
<script>

ということは

Q.

他のコンポーネントに useCounter2 の機能だけを入れたいとき
どうする?

    1. useCounter2.jsの中身をコピペする
    1. useCounter2.jsをインポートする

A.

  1. useCounter2.jsをインポートする

いろんな画面共通で使う機能を切り出せば
インポートするだけでお手軽に画面がつくれる

夢、広がる!

@vue/composition-apiパッケージを導入すれば
Vue2系のプロジェクトでも使うことができます
https://www.npmjs.com/package/@vue/composition-api

また、省略したけれど、typescriptとの相性もよくなります

参考資料
https://v3.vuejs.org/guide/composition-api-introduction.html

おわり

口頭解説前提の資料のため、ドキュメント単体では理解しづらい面もあるかもしれません。
いいねやご指摘あればぜひお願いいたします。

Discussion