Composition API とは
コンポーネントの柔軟な合成を可能にする関数ベースのAPIです
Composition Function によりロジックの関心ごとにコードをまとめやすくなるのと、
型推論の改善も組み込まれているようです。
以前はコンポーネントでロジックを使いまわしたい時は mixin を使う必要がありましたが、namespace の衝突の問題がありました。 ( this.~ )
今回はとりあえず Option API からの書き換えをメインに書きたいと思います。
開発環境
型推論 の機能もあるということで、 vue-cli で TypeScript 対応のプロジェクトを作成して試してみました
TypeScript 対応はこちらを参考にさせていただきました
$ vue create your-project-name
# オプションの class-style component は今回使わないので No にしました
Vue2系で Composition API を使うには @vue/composition-api が必要なのでインストールします
$ npm i @vue/composition-api
main.ts に 2 行追加します
import Vue from 'vue';
import App from './App.vue';
import VueCompositionApi from '@vue/composition-api'; // 追加
Vue.use(VueCompositionApi); // 追加
Vue.config.productionTip = false;
new Vue({
render: (h) => h(App),
}).$mount('#app');
これで準備完了です!
Options API からの書き換え
Options API は Vue の基本的な記述法です
テンプレート/スタイル部分のコードは省略します!
props
- こちらは特に変化なしですね
-
setupの第一引数で props を使用できます - setup はこのあと出てきますが、初期化を行うような関数です
export default {
props: {
list: {
type: Array,
default: [],
},
},
setup(props){
}
}
data
-
reactiveを使って、setupの中に定義します- props のように例外もありますが、基本 setup の中に定義していく感じです
- setup で
stateを return します -
state.{プロパティ名}で参照できます
import { reactive } from '@vue/composition-api';
export default {
setup() {
const state = reactive({
items: [],
newItem: ''
});
return { state }
}
}
ですが、 ↓ のように toRefs を使うのがおすすめみたいです
こうすることで、テンプレート部分で state を介さず直接プロパティ名で参照できるようになります
import { reactive, toRefs } from '@vue/composition-api';
export default {
setup() {
const state = reactive({
items: [],
newItem: ''
});
return { ...toRefs(state) }
}
}
computed
-
computedを使います
import { reactive, toRefs, computed } from '@vue/composition-api';
export default {
setup() {
const state = reactive({
items: [],
newItem: ''
});
const totalCount = computed(() => {
return state.items.length;
});
return { ...toRefs(state), totalCount }
}
}
methods
- 普通に関数を定義するだけです、 return もお忘れなく
import { reactive, toRefs } from '@vue/composition-api';
export default {
setup() {
const state = reactive({
items: [],
newItem: ''
});
const addItem = () => {
state.items.push(state.newItem);
newItem = '';
};
return { ...toRefs(state), addItem }
}
}
watch
-
watchEffectを使います - Option API の watch との違いは、 watchEffect の中で参照されているオブザーバブルな値が変更された場合に実行されます
import { reactive, toRefs, watchEffect } from '@vue/composition-api';
export default {
setup() {
const state = reactive({
items: [],
newItem: ''
});
watchEffect(() => {
console.log(state.items);
});
return { ...toRefs(state) }
}
}
emit
- setup の第二引数 context を使って
context.emitで実行 - キャメルケース使用不可。ケバブケースで記述する必要あり
export default {
setup(props, context) {
context.emit('value-change');
}
ライフサイクルフック
-
on~の形で使えます
import { onMounted } from '@vue/composition-api';
export default {
setup() {
onMounted(() => {
console.log('mounted!');
});
}
}
型推論を効かせる
- TypeScript で書く場合、
defineComponentで setup に渡された引数の型推論を効かせることができるようになります - props の型は
PropTypeを使用します
例えばこんなコードの時
import { PropType, toRefs }
export default {
props: {
list: {
type: Array as PropType<string[]>,
default: [],
},
},
setup(props) {
const state = reactive<{ newItem: string }>({ newItem: '' });
const addItem = () => {
props.list.push(''); // <= 注目
state.newItem = 0; // <= 注目
};
return { ...toRefs(state), addItem }
}
}
まず state.newItem のほうは、 string 型に指定しているのでエラーになっています
型推論が効いていますね

props.list のほうは 型情報が不明になっていますね...

これに defineComponent を使用します(全体を囲うだけ)
import { defineComponent, PropType, toRefs }
export default defineComponent({
props: {
list: {
type: Array as PropType<string[]>,
default: [],
},
},
setup(props) {
const state = reactive<{ newItem: string }>({ newItem: '' });
const addItem = () => {
props.list.push('');
state.newItem = 0;
};
return { ...toRefs(state), addItem }
}
})
マイグレーションについて
Vue2 から Vue3 への マイグレーションは vue-codemod を使えば簡単にできるとのことですが、Option API から Composition API へのマイグレーションは、少なくとも今のところは手動でやるしかないみたいですね...
おわりに
今回は試せなかったのですが、 Composition Function も実装してみたいです。
おそらくここが Composition API の肝な気がする...
Composition Functionとは、関連するロジックでまとめられ、カプセル化された関数のことです。Composition APIによってthisへの依存がなくなり、コードは関心ごとでまとめられるようになりました。まとめられた関数は純粋なJavaScript or TypeScriptの関数として抽出し、他のコンポーネントで再利用しやすくなります。
https://techblog.zozo.com/entry/vue-options-api-to-composition-api#Composition-Function
