NuxtMeetup#9@メルペイ
自己紹介
かいしゃ 株式会社ROXX
なまえ ushironoko
しごと フロントエンド
すき アイマス
@dreamroot46
みなさんFunction APIやってますか?
composition-api
要約
・Vue 3.0で追加される関数ベースでコンポーネントが書けるAPI
・コンポーネントを返したり返さなかったりする
・mixinとかHOCの代わりになれる
・コンポーネントの外にいたりいなかったりする
- 名前の衝突がない
- 不要なインスタンス作らない
・ちゃんと型が効く
いつ使えるの?
・Vue 3からコアに入る
・Vue 2系の場合プラグインで使える
・NuxtのAPIはまだ未対応
Nuxtでの使い方(ついでにTS対応)
・create-nuxt-app(Lint + Prettier)
・yarn add @nuxt/typescript-runtime
@vue/composition-api
・yarn add -D @nuxt/typescript-build
@typescript-eslint/eslint-plugin @typescript-eslint/parser
諸々入れる※v2.9.0以降
Nuxtでの使い方(ついでにTS対応)
諸々設定
・tsconfig.jsonに設定追加
・nuxt.config.jsをts化 & nuxt-ts devなどに書き換え、その他諸々追加
・.eslint.jsに設定追加
だいたいNuxt TypeScriptのドキュメントにあります
Nuxt TypeScript
Nuxtでの使い方(ついでにTS対応)
・plugins/composition-api.js
import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'
Vue.use(VueCompositionApi)
・nuxt.config.ts
//省略
plugins: ['~/plugins/composition-api'],
// 省略
<template>
<div>
<div>{{ `x: ${x}` }}</div>
<div>{{ `y: ${y}` }}</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { ref, onMounted, onUnmounted } from '@vue/composition-api'
export default Vue.extend({
setup() {
const x = ref(0)
const y = ref(0)
const update = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
})
</script>
いつものマウスのやつ(useMouse的な)
・コンポーネントに依存した処理じゃないし外に出したい
お気持ち
・コンポーネントよりも小さい単位(関数)で分割したい
・多分こんな感じになってアレ
import mouse from '~/utils/mouse'
// 省略
methods: {
mouse(val) {
return mouse(val)
}
}
compositions/useMouse.ts
import { ref, onMounted, onUnmounted } from '@vue/composition-api'
export default () => {
const x = ref(0)
const y = ref(0)
const update = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
・リアクティブな値をコンポーネントの外で作れる
pages/index.vue
<template>
<div>
<h1>Nuxt + vue-function-api</h1>
<div>{{ `x: ${x}` }}</div>
<div>{{ `y: ${y}` }}</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import useMouse from '~/compositions/useMouse'
export default Vue.extend({
setup() {
const { x, y } = useMouse() // x: Wrapper<number> y: Wrapper<number>
return { x, y }
}
})
</script>
・ばっちり型も効く(Wrapper<T>型になる)
よさそう
Composition API Document
Composition API 所感
・処理をコンポーネントから抽出できる
・直感的に型が効いてうれしい
・普通の関数以上コンポーネント未満ができる
- リアクティブな関数を自作できる
・thisとおさらばできる
Nuxt要素薄まってきたのでNuxtの話します
NuxtとComposition API
・asyncDataがない
・fetchがない
・contextに色々入ってない
・slots
・attrs
・emit
VueのContextはある
・parent
・root
・refs
Nuxt独自のものは未対応
Nuxtでの使い方
・Object APIとキメラにする
<script>
import Vue from 'vue'
import useMouse from '~/compositions/useMouse'
export default Vue.extend({
props: {
id: Number
},
setup() {
return {
...useMouse()
}
},
asyncData() {
...
},
data() {
...
}
})
</script>
キメラにしたときの動作
・setup → Object APIの順に実行される
・setupで返した値はthisで参照可能
・asyncDataやfetchがある場合setupの前に実行される
setup() {
return {
count: 1000
}
},
mounted() {
console.log(this.count) // 1000 ミツケター!
}
キメラにしたときの動作
・Object APIと競合するプロパティは上書きされる
・setupの中でしかComposition APIは動かない
・setupにasyncDataの値が渡せない
setup(props, ctx) {
// IIKO ワドコドコ…
},
asyncData() {
return {
IIKO: 'IIKO'
}
}
ただし子にpropsとして渡せば可能
<template>
<div>
<v-counter :initial-count="count"></v-counter>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import VCounter from '~/components/VCounter.vue'
export default Vue.extend({
components: {
VCounter
},
asyncData() {
return { count: 100 }
},
data() {
return {
count: 0
}
}
})
</script>
・pages/index.vue
<template>
<div>
{{ count }}
<button @click="increment">+</button>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import useCount from '~/compositions/useCount'
export default Vue.extend({
props: {
initialCount: {
type: Number,
default: 0
}
},
setup(props) {
return {
...useCount(props.initialCount)
}
}
})
</script>
子のsetupでcomposition functionに渡す
・components/VCounter.vue
よさそう
注意点
asyncData() {
console.log('asyncData')
return {
count1: 1,
count2: 2
}
},
setup() {
console.log('setup')
return {
count1: 1000,
count2: 2000,
count3: 3000
}
},
mounted() {
console.log(this.count1)
console.log(this.count2)
console.log(this.count3)
}
setupはasyncDataに負ける
注意点
setupはasyncDataに負ける
注意点
setupの型が死んでる(v2.9.0〜)
まとめ
・Nuxtでもpluginsで登録すれば使える
・コンポーネントを返さない純粋な関数としても有用
・NuxtのAPIはないが、一部は設計次第で対応可能
・あくまでRFC、ご利用は自己責任で
参考
・追記:@vue/composition-apiに代わり内容も若干変更されたのでスライド追従しました
Thank You!