Search code examples
vue.jsvuejs3reactivepinia

vue3 + pinia: how to make reactive a value from the store


I am using vue 3 with composition api and pinia

I have an auth store that is reading from the store a default email and a default password

import { useAuthStore } from "stores/auth";
const authStore = useAuthStore();

const email = authStore.loginUser;
const password = authStore.passwordUser;

Then I am using email and password as v-model.

The problem is that both are not reactive. If I change the value from the text input, the model is not updated

I ask kindly for an explanation of the problem and a solution.


Solution

  • // ❌ loses reactivity
    const email = authStore.loginUser 
    

    creates an email constant with the current value of authStore.loginUser, losing reactivity. To keep reactivity, you could use computed:

    import { computed } from 'vue'
    
    // ✅ keeps reactivity
    const email = computed({
      get() { return authStore.loginUser },
      set(val) { authStore.loginUser = val }
    })
    // email is now a computed ref
    

    ...or you could use the provided storeToRefs wrapper, designed for extracting/deconstructing store reactive props while keeping their reactivity (basically to avoid the above boilerplate):

    import { storeToRefs } from 'pinia'
    // ✅ keeps reactivity
    const { 
      loginUser: email,
      passwordUser: password
    } = storeToRefs(authStore)
    // email & password are now refs
    

    Important: you only want to deconstruct state and getters using storeToRefs. Actions should be used directly from the store object (authStore in your case) or deconstructed without the wrapper:

    const { actionOne, actionTwo } = authStore
    

    This is specified in docs linked above:

    ... so methods and non reactive properties are completely ignored.


    In conclusion, you typically end up with two deconstructions from each store:

    import { useSomeStore } from '@/store'
    // reactive:
    const { s1, s2, g1, g2 } = storeToRefs(useSomeStore())
    // non-reactive:
    const { a1, a2 } = useSomeStore()
    

    where s1, s2 are state members, g1, g2 are getters and a1, a2 are actions.