親から孫など、離れたコンポーネント間で値を渡す場合は、provide/injectを使うことができます。
公式Doc
親側(Provide:提供)
ParentPage.vue
<template>
<ChildComponent />
</template>
<script setup lang="ts">
import ChildComponent from 'src/components/ChildComponent.vue';
import { provide } from 'vue';
const func = (val:ArgsType):ReturnType => {
...
}
provide('key1', 'params');
provide('key2', func);
provide('key3', (): void => {
console.log('fugafuga')
}
);
</script>
子側(Inject:注入)
ChildComponent.vue
<template>
{{ key1Inject }}
{{ key2Inject!(hogehgoe) }}
{{ key3Inject }}
{{ key3Inject!() }}
</template>
<script setup lang="ts">
import { inject } from 'vue';
const key1Inject = inject<string>('key1');
const key2Inject = inject<(val:ArgsType) => ReturnType>('key2');
const key2Inject = inject<() => void>('key3');
const hogehoge: ArgsType = ...;
if (key1Inject) {
key1Inject;
...
}
if (key2Inject) {
key2Inject(hogehoge);
...
}
</script>
TypeScript環境で使う場合の注意点
親子間で型の同期が取れない
TypeScript側では親子の型情報を見てくれません。
書き間違えてもエラーの指摘がされないので、慎重に使う必要があると思います。
Inject側の型情報は書くべき
子で受け取る際に、ジェネリクスで型情報を入れることができます。
これをやらないと子の中で型指定の恩恵が受けられません。
無くても動きはしますが。。。
undefinedの可能性を指摘される(if文や非nullアサーション演算子で回避が必要)
子コンポーネントでは、確実に値が渡ってくるか判別できません。
そのため型情報としては、Type | undefined
となります。
undefinedを回避するための記述が必要です。
template内での使い方にはいくつか種類がある
引数を取らず、値をそのまま使う場合は、非nullアサーション演算子が不要なようです。