Search code examples
vue.jsvue-routerpinia

getActivePinia was called with no active Pinia. Vue


i get this error: Uncaught Error: [🍍]: getActivePinia was called with no active Pinia. Did you forget to install pinia? const pinia = createPinia() app.use(pinia) This will fail in production. at useStore (pinia.mjs:1691:19) at PokemonDetails.vue:3:22

what's wrong with my code?

pokemonDetails:

<script>
import { usePokemonStore } from '../stores/PokemonStore';
const pokemonStore = usePokemonStore();
export default {
  name: 'PokemonDetails',
  methods: {
    evolutions() {
      return [
        pokemonStore.evolutionOne,
        pokemonStore.evolutionTwo,
        pokemonStore.evolutionThree,
      ];
    },
    resetApp() {
      this.$router.push('/');
      pokemonStore.$reset();
    },
  },
};
</script>

<template>
  <template v-if="pokemonStore.findPokemon == false">
    <div class="firstDiv">
      <div class="secondDiv">
        <div>
          <strong>{{ pokemonStore.pokemonName }}</strong
          ><img :src="pokemonStore.selfie" alt="foto de pokemon" />
          <p>Elemento Principal: {{ pokemonStore.type }}</p>
        </div>
        <div>
          <strong>Habilidades:</strong>
          <ul>
            <li v-for="stat in pokemonStore.stats[0]">
              {{ stat.stat.name }}: +{{ stat.base_stat }}
            </li>
          </ul>
        </div>
      </div>
      <div class="divEvolutions">
        <strong>Evolução</strong>
        <ul class="evolutions">
          <li v-for="evolution in evolutions">
            <img :src="evolution.selfie" />
            {{ evolution.name }}
          </li>
        </ul>
      </div>
      <button v-on:click="resetApp" class="newSearch">Nova pesquisa</button>
    </div>
  </template>
</template>

<style lang="scss" scoped>
.firstDiv {
  text-align: center;
}
.secondDiv {
  display: grid;
  justify-items: center;
  align-items: center;
  grid-template-columns: repeat(2, 1fr);
  max-height: 600px;
  width: 400px;
  padding: 20px;
  border-radius: 1.5rem;
  background-color: $gray-200;
  div {
    display: flex;
    flex-direction: column;
  }
}
.divEvolutions {
  background-color: $gray-200;
  border-radius: 1.5rem;
  margin-top: 10px;
}
.evolutions {
  display: flex;
  justify-content: center;
  align-items: center;
  li {
    display: flex;
    flex-direction: column;
  }
}
.newSearch {
  margin-top: 10px;
  padding: 5px;
  border-radius: 1rem;
  background-color: $gray-200;
  transition-duration: 500ms;
  &:hover {
    background-color: black;
    color: $gray-200;
  }
}
</style>

pokemonStore.js:

import { defineStore } from 'pinia';

export const usePokemonStore = defineStore('pokemon', {
  state: () => ({
    findPokemon: true,
    pokemonName: '',
    speciesLink: '',
    selfie: '',
    type: '',
    stats: [],
    evolutionOne: {},
    evolutionTwo: {},
    evolutionThree: {},
  }),
  getters: {},
  actions: {
    addPokemon(
      name,
      species,
      selfie,
      type,
      stats,
      evolutionOne,
      evolutionTwo,
      evolutionThree
    ) {
      this.pokemonName = name;
      this.speciesLink = species;
      this.selfie = selfie;
      this.type = type;
      this.stats.push(stats);
      this.findPokemon = false;
      this.evolutionOne = evolutionOne;
      this.evolutionTwo = evolutionTwo;
      this.evolutionThree = evolutionThree;
    },
  },
});

main.js:

import { createApp } from 'vue';
import { createPinia } from 'pinia';

import App from './App.vue';
import router from './router';

import './assets/main.css';

const app = createApp(App);

app.use(createPinia());
app.use(router);

app.mount('#app');

i tried call my store in computed:

  computed: {
    pokemonStore() {
      return usePokemonStore();
    },
    evolutions() {
      return [
        this.pokemonStore.evolutionOne,
        this.pokemonStore.evolutionTwo,
        this.pokemonStore.evolutionThree,
      ];
    },
  },

it works, but i believe is don't the best practices


Solution

  • Stores aren't supposed to be used before Pinia is installed to Vue application.

    The reason why use... composables are created by Pinia defineStore instead of store objects is that this allows to avoid race conditions.

    Here usePokemonStore is called on pokemonDetails import before Pinia install. pokemonStore is referred in the template while it's not a part of component instance. For a component with options API it should be:

      name: 'PokemonDetails',
      data() {
        return { pokemonStore: usePokemonStore() }
      },