概要
Nuxt3 と Vuetify を使って SPA を実装しています。 ログイン成功したときなどに、 遷移先に Snackbar でメッセージを表示させたいと考えました。 ところが、以下のように pages 配下のコンポーネントに Snackbar を書くと、遷移先のページには Snackbar を表示することができませんでした。
<script lang="ts" setup> const message = ref<string | null>(null); </script> <template> <v-main> <v-btn @click="message='ログインに成功しました。'">ログイン</v-btn> <v-snackbar :model-value="message !== null">{{ message }}</v-snackbar> </v-main> </template>
そこで、 以下のようなプログラムを実装しました。
- レイアウトで、
v-snackbar
に表示する文字列を更新する関数を子コンポーネント( Page コンポーネント)に provide する。 - 1 で provide した関数を 子コンポーネント(Page コンポーネント)に inject して利用する。
実装したプログラム
公式ガイドを参考に実装しました。
1. レイアウトで、 v-snackbar
に表示する文字列を更新する関数を子コンポーネントに provide する。
export const SNACKBAR_PROVIDE_KEY = Symbol() as InjectionKey<{ showSnackbar: (message: string) => void }>;
<script lang="ts" setup> const _message = ref<string | null>(null); function showSnackbar(message: string) { _message.value = message; } provide(SNACKBAR_PROVIDE_KEY, { showSnackbar: showSnackbar }); </script> <template> <div> <v-app> <slot/> <v-snackbar :model-value="_message !== null">{{ _message }} </v-snackbar> </v-app> </div> </template>
2. 1 でprovide した関数を 子コンポーネント(Page コンポーネント)に inject して利用する。
<script lang="ts" setup> const { showSnackbar } = inject(SNACKBAR_PROVIDE_KEY) as typeof SNACKBAR_PROVIDE_KEY extends InjectionKey<infer T> ? T : never; </script> <template> <v-main> <v-btn @click="showSnackbar('ログインに成功しました。')">ログイン</v-btn> </v-main> </template>
最後に
グローバルに近い状態と状態を変更する関数を公開するのは、あまり良いパターンではないかもしれません。 ただ、 Snackbar をページ遷移とは切り離して管理したいと思ったので、このような実装を考えました。 もし、もっとスマートなやり方があれば教えていただけると嬉しいです。