Vue3 コンポジション API
Vue3 コンポジション API(Composition API)は、主に大規模なコンポーネントでコードロジックの再利用性を高めるために使用されます。
従来のコンポーネントは、ビジネスの複雑さが増すにつれてコード量が増え続け、コードロジック全体が読みにくく理解しにくくなります。
Vue3 でコンポジション API を使用するのは次の場所です。setup。
setup 内では、論理的な関心ごとにコードの一部をグループ化し、ロジックの断片を抽出して他のコンポーネントとコードを共有できます。したがって、コンポジション API(Composition API)により、より整理されたコードを書くことができます。
以下の2つのコードを比較してください。
1. 従来のコンポーネント

2. コンポジション API

setup コンポーネント
setup() 関数は、コンポーネント作成の created() より前に実行されます。
setup() 関数は、props と context の2つの引数を受け取ります。
最初の引数 props はリアクティブであり、新しい prop が渡されると更新されます。
2番目の引数 context は通常の JavaScript オブジェクトであり、setup 内で役立つ可能性のある他の値を公開するコンテキストオブジェクトです。
注意:setup 内では this の使用を避けるべきです。this はコンポーネントインスタンスを見つけられないためです。setup の呼び出しは data property、computed property、methods が解析される前に行われるため、これらを setup 内で取得することはできません。
次の例では、コンポジション API を使用してカウンターを定義します。
例(src/APP.vue)
<div>
<p>カウンターの例: {{ count }}</p>
<input @click="myFn" type="button" value=「クリックで +1」>
</div>
</template>
<script>
import {ref, onMounted} from 'vue';
export default {
setup(){
// 初期値0の変数を定義するには、ref メソッドを使用して代入します。直接代入すると変数が変更されても UI は更新されません。
let count = ref(0);
// クリックイベント myFn を定義します
function myFn(){
console.log(count);
count.value += 1;
}
// コンポーネントがマウントされたとき、onMounted フックを使ってメッセージを記録します。
onMounted(() => console.log('component mounted!'));
// コンポジション API で定義した変数やメソッドは、外部(テンプレート内)で使用できます。
return {count,myFn} // 返された関数はメソッドと同じように動作します
}
}
</script>
Vue 3.0 では、新しい ref 関数を使うことで、任意のリアクティブ変数をどこでも機能させることができます。次のようにします。
import { ref } from 'vue'
let count = ref(0);
ref()この関数は、指定された値に基づいてリアクティブなデータオブジェクトを作成します。戻り値はオブジェクトであり、含まれるのは.valueプロパティのみです。
setup() 関数内では、ref() が作成するリアクティブデータはオブジェクトを返すため、アクセスには.value.value を使用する必要があります。
例
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
counter.value++
console.log(counter.value) // 1
Vue コンポジション API ライフサイクルフック
Vue2 では、次の方法でライフサイクルフック関数を実装します。
例
beforeMount() {
console.log('V2 beforeMount!')
},
mounted() {
console.log('V2 mounted!')
}
};
Vue3 コンポジション API でライフサイクルフック関数を実装するには、setup()setup() 関数内で、接頭辞(プレフィックス)としてonon を持つ関数を使用します:
例
export default {
setup() {
onBeforeMount(() => {
console.log('V3 beforeMount!');
})
onMounted(() => {
console.log('V3 mounted!');
})
}
};
次の表は、Options API と Composition API の対応関係を示し、setup() 内でライフサイクルフックを呼び出す方法も含んでいます。
| Vue2 Options-based API | Vue Composition API |
|---|---|
| beforeCreate | setup() |
| created | setup() |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeDestroy | onBeforeUnmount |
| destroyed | onUnmounted |
| errorCaptured | onErrorCaptured |
setup は beforeCreate と created のライフサイクルフックの周囲で実行されるため、これらを明示的に定義する必要はありません。言い換えれば、これらのフックで記述するコードはすべて、直接 setup 関数内に記述する必要があります。
これらの関数はコールバック関数を受け取り、フックがコンポーネントによって呼び出されたときに実行されます:
例
...
// コンポーネントがマウントされたとき、onMounted フックを使ってメッセージを記録します。
onMounted(() => console.log('component mounted!'));
...
}
テンプレート参照
コンポジション API を使用する場合、リアクティブ参照とテンプレート参照の概念は統一されています。
テンプレート内の要素やコンポーネントインスタンスへの参照を取得するには、通常どおり ref を宣言して setup() から返すことができます:
例
<div ref="root">This is a root element</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// DOM 要素は初期レンダリング後に ref に割り当てられます
console.log(root.value) // <div>This is a root element</div>
})
return {
root
}
}
}
</script>
上記の例では、レンダリングコンテキストで root を公開し、ref="root" によって div にその ref としてバインドしています。
テンプレートで使用される ref の動作は、他の ref と同様です。それらはリアクティブであり、複合関数に渡す(または複合関数から返す)ことができます。
v-for 内での使用法
コンポジション API のテンプレート参照は、v-for 内で使用する場合に特別な処理はありません。代わりに、関数参照を使用してカスタム処理を実行してください:
例
<div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }">
{{ item }}
</div>
</template>
<script>
import { ref, reactive, onBeforeUpdate } from 'vue'
export default {
setup() {
const list = reactive([1, 2, 3])
const divs = ref([])
// 毎回の更新前に ref をリセットします
onBeforeUpdate(() => {
divs.value = []
})
return {
list,
divs
}
}
}
</script>
テンプレート参照の監視
テンプレート参照の変更を監視することで、前述の例で使用したライフサイクルフックの代わりにすることができます。
ただし、ライフサイクルフックとの重要な違いは、watch() と watchEffect() が DOM のマウントまたは更新の前に実行されると副作用が生じる可能性があり、リスナーが実行された時点ではテンプレート参照がまだ更新されていないことです。
例
<div ref="root">This is a root element</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const root = ref(null)
watchEffect(() => {
// この副作用は DOM 更新前に実行されるため、テンプレート参照はまだ要素への参照を保持していません。
console.log(root.value) // => null
})
return {
root
}
}
}
</script>
したがって、テンプレート参照を使用するリスナーは、flush: 'post' オプションを指定して定義する必要があります。これにより、DOM 更新後に副作用が実行され、テンプレート参照が DOM と同期し、正しい要素を参照することが保証されます。
例
<div ref="root">This is a root element</div>
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const root = ref(null)
watchEffect(() => {
console.log(root.value) // => <div>This is a root element</div>
},
{
flush: 'post'
})
return {
root
}
}
}
</script>
API リファレンス
| 番号 | API と説明 | 例 |
|---|---|---|
| 1 | setup() コンポーネントのコンポジション API におけるエントリ関数で、コンポーネントのインスタンス化時に呼び出され、リアクティブデータとメソッドを定義するために使用します。 | export default { setup() { const count = ref(0); return { count }; } } |
| 2 | ref() 基本型またはオブジェクトをラップするためのリアクティブ参照を作成します。 | const count = ref(0) |
| 3 | computed() 他のリアクティブデータに基づいて計算された値を作成します。 | const doubledCount = computed(() => count.value * 2) |
| 4 | reactive() リアクティブオブジェクトを作成します。オブジェクトや配列に適しています。 | const state = reactive({ count: 0 }) |
| 5 | readonly() 読み取り専用のリアクティブデータを作成し、変更を禁止します。 | const state = readonly({ count: 0 }) |
| 6 | watchEffect() リアクティブな副作用を作成し、関連するリアクティブな依存関係を自動的に追跡します。 | watchEffect(() => { console.log(count.value) }) |
| 7 | watchPostEffect() DOM 更新後にトリガーされる副作用。 | watchPostEffect(() => { console.log('Post effect') }) |
| 8 | watchSyncEffect() リアクティブな依存関係が変化したときに副作用を同期的に実行します。 | watchSyncEffect(() => { console.log('Synchronized effect') }) |
| 9 | watch() リアクティブデータの変更を監視するために使用します。特定のリアクティブデータや算出プロパティを指定できます。 | watch(count, (newCount) => { console.log(newCount) }) |
| 10 | onWatcherCleanup() リスナーをクリーンアップするために、監視対象のデータが不要になったときに呼び出します。 | watch(count, () => {}, onWatcherCleanup(() => { console.log('cleaned up') })) |
| 11 | isRef() 値が refref 型であるかどうかを確認します。 | isRef(count) |
| 12 | unref() ref の値を refアンラップします。 | unref(count) |
| 13 | toRef() オブジェクトから抽出したリアクティブ参照を作成します。 | const countRef = toRef(state, 'count') |
| 14 | toValue() ref 型の値を ref 或 reactiveアンラップします。 | toValue(count) |
| 15 | toRefs() リアクティブオブジェクトの各プロパティを独立した ref に変換します。 ref。 | const { count } = toRefs(state) |
| 16 | isProxy() オブジェクトが Vue のプロキシオブジェクトであるかどうかを確認します。 | isProxy(state) |
| 17 | isReactive() オブジェクトがリアクティブオブジェクトであるかどうかを確認します。 | isReactive(state) |
| 18 | isReadonly() オブジェクトが読み取り専用のリアクティブオブジェクトであるかどうかを確認します。 | isReadonly(state) |
| 19 | shallowRef() 浅い ref を作成し、 refオブジェクトの第一レベルのプロパティのみをリアクティブにします。 | const state = shallowRef({ count: 0 }) |
| 20 | triggerRef() ref の更新を強制的に refトリガーします。 | triggerRef(count) |
| 21 | customRef() 開発者が getter と setter をカスタマイズできる、カスタムのリアクティブ参照を作成します。 | const count = customRef((track, trigger) => { let value = 0; return { get: () => value, set: (val) => { value = val; trigger() } } }) |
| 22 | shallowReactive() 浅いリアクティブオブジェクトを作成します。オブジェクトの第一レベルのプロパティのみがリアクティブです。 | const state = shallowReactive({ count: 0 }) |
| 23 | shallowReadonly() 浅い読み取り専用のリアクティブオブジェクトを作成します。オブジェクトの第一レベルのプロパティのみが読み取り専用です。 | const state = shallowReadonly({ count: 0 }) |
| 24 | toRaw() プロキシオブジェクトの元のオブジェクトを取得します。 | const rawState = toRaw(state) |
| 25 | markRaw() オブジェクトをプロキシ不可としてマークします。Vue はそのオブジェクトのリアクティブ処理をスキップします。 | const obj = markRaw({ count: 0 }) |
| 26 | effectScope() 副作用を管理するための新しい effect scope を作成します。 | const scope = effectScope() |
| 27 | getCurrentScope() 現在の effect scope を取得します。 | const scope = getCurrentScope() |
| 28 | onScopeDispose() effect scope が破棄されたときにクリーンアップ関数を実行します。 | onScopeDispose(() => { console.log('Scope disposed') }) |
| 29 | onMounted() コンポーネントのマウント完了時に呼び出されるライフサイクルフック。 | onMounted(() => { console.log('Component mounted') }) |
| 30 | onUpdated() コンポーネント更新時に呼び出されるライフサイクルフック。 | onUpdated(() => { console.log('Component updated') }) |
| 31 | onUnmounted() コンポーネントのアンマウント時に呼び出されるライフサイクルフック。 | onUnmounted(() => { console.log('Component unmounted') }) |
| 32 | onBeforeMount() コンポーネントのマウント前に呼び出されるライフサイクルフック。 | onBeforeMount(() => { console.log('Before mount') }) |
| 33 | onBeforeUpdate() コンポーネントの更新前に呼び出されるライフサイクルフック。 | onBeforeUpdate(() => { console.log('Before update') }) |
| 34 | onBeforeUnmount() コンポーネントのアンマウント前に呼び出されるライフサイクルフック。 | onBeforeUnmount(() => { console.log('Before unmount') }) |
| 35 | onErrorCaptured() コンポーネントツリー内の未処理のエラーをキャプチャします。 | onErrorCaptured((err, instance, info) => { console.error(err) }) |
| 36 | onRenderTracked() コンポーネントのレンダリング中に、リアクティブデータが追跡されたときにトリガーされるフック。 | onRenderTracked((event) => { console.log(event) }) |
| 37 | onRenderTriggered() コンポーネントのレンダリング中に、リアクティブデータが変更されたときにトリガーされるフック。 | onRenderTriggered((event) => { console.log(event) }) |
| 38 | onActivated() コンポーネントがアクティブ化されたときに呼び出されるライフサイクルフック( keep-aliveコンポーネント | onActivated(() => { console.log('Component activated') }) |
| 39 | onDeactivated() コンポーネントが非アクティブ化されたときに呼び出されるライフサイクルフック( keep-aliveコンポーネント)。 | onDeactivated(() => { console.log('Component deactivated') }) |
| 40 | onServerPrefetch() コンポーネントがサーバーサイドレンダリング時にデータをプリフェッチするフック。 | onServerPrefetch(async () => { await fetchData() }) |
| 41 | provide() 依存関係を子孫コンポーネントに渡す。 | provide('key', value) |
| 42 | inject() 親コンポーネントまたは祖先コンポーネントから依存関係を注入する。 | const value = inject('key') |
| 43 | hasInjectionContext() 現在に注入コンテキストがあるかどうかを確認する。 | hasInjectionContext() |
| 44 | useAttrs() コンポーネントに渡されたHTML属性を含む、コンポーネントのすべての属性を取得する。 | const attrs = useAttrs() |
| 45 | useSlots() コンポーネントのスロットコンテンツを取得する。 | const slots = useSlots() |
| 46 | useModel() 現在のコンポーネントの v-modelバインドされた値。 | const modelValue = useModel() |
| 47 | useTemplateRef() テンプレート内の要素の参照を取得する。 | const templateRef = useTemplateRef('elementId') |
| 48 | useId() 一意の識別子を取得する。 | const uniqueId = useId() |