[Vue] Provide and Inject Global Storage

Zhentiw發表於2024-11-26

There are several ways to solve this problem, but as always I want to show you the simplest, cleanest solution. We have three steps with my solution:

  1. Create a global storage mechanism to store our flash message.
  2. Set the flash message for registration inside our Register.vue.
  3. Create a place where the flash message is displayed in our App.vue.

Step 1: Global Storage

You might be thinking, “Isn’t this what Vuex is for? To have a global storage mechanism which can be accessed from different parts of my Vue app?” The answer is yes, this is exactly the problem that Vuex solves. However, Vuex can be complex to understand (and you don’t need to know it yet if you’re just learning) and we can use a simpler (and still elegant) solution for now thanks to Vue 3.

Vue 3 decoupled reactivity from components. This allows us to declare a reactive object independent of our components, and then inject that reactive object to the components who need it. Back in our main.js where our Vue instance is created we can create a Global Store, we’ll call GStore.

📄 /src/main.js

import { createApp, reactive } from "vue";
import App from "./App.vue";
import router from "./router";

const app = createApp(App);

app.use(router);

// Create a reactive object
const GStore = reactive({ flashMessage: '' })
app.provide('GStore', GStore)  // provide this object so others can inject it

app.mount('#app')

Be sure to read the comments in the code above. You can think of GStore as a JavaScript Object which has reactivity, meaning that when any properties get changed it will be updated on our webpage. You can learn more about the reactive syntax in my Vue 3 Composition API course, so I won’t go into more detail here.

Provide has been around since Vue 2, and it allows us to specify data that we want inject into other components. You can think of it as an alternative to using props and events for component communication. We’ll use inject next to access it.

Step 2: Create the Flash Message

Back inside our Register component, we can now inject our GStore and use it to store our flashMessage:

📄 /src/views/event/Register.vue

<script setup>
import { useRouter } from 'vue-router'
import { defineProps, inject } from "vue";

const { event } = defineProps(['event'])
const router = useRouter()
const GStore = inject('GStore')

const register = () => {
  // Call to API
  // If registered then redirect to event details
  GStore.flashMessage = 'You are successfully registered for ' + event.title
  setTimeout(() => {
    GStore.flashMessage = ''
  }, 3000)
  router.push({
    name: 'EventDetails'
  })
}
</script>

Two things to notice above. First the inject component option, which gives our component access to our GStore. Then we set our flash message, and set a Timeout so that the flashMessage is cleared after 3 seconds.

Step 3: Displaying the Flash Message

Many components in our application will be creating these user messages, so we need to display this in our main layout, which in our app is our App.vue:

📄 /src/views/App.vue

<script setup>
import { inject } from 'vue'

const GStore = inject('GStore') // <----
</script>

<template>
  <div id="app">
    <div id="flashMessage" v-if="GStore.flashMessage">
      {{ GStore.flashMessage }}
    </div>
    ...
</template>

<style>
@keyframes yellowfade {
  from {
    background: yellow;
  }
  to {
    background: transparent;
  }
}

#flashMessage {
  animation-name: yellowfade;
  animation-duration: 3s;
}

...
</style>

相關文章