くちたと計算記

プログラミングのことを書きます

Nuxt3 で Provide / Inject を使って画面遷移先に Vuetify の Snackbar を表示させる

概要

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>

そこで、 以下のようなプログラムを実装しました。

  1. レイアウトで、 v-snackbar に表示する文字列を更新する関数を子コンポーネント( Page コンポーネント)に provide する。
  2. 1 で provide した関数を 子コンポーネント(Page コンポーネント)に inject して利用する。

実装したプログラム

公式ガイドを参考に実装しました。

ja.vuejs.org

ja.vuejs.org

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 をページ遷移とは切り離して管理したいと思ったので、このような実装を考えました。 もし、もっとスマートなやり方があれば教えていただけると嬉しいです。

参考 Web サイト

ja.vuejs.org

ja.vuejs.org