8

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.

realtebo
  • 23,922
  • 37
  • 112
  • 189

1 Answers1

12
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'
// ...

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'
// ...

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.

tao
  • 82,996
  • 16
  • 114
  • 150
  • IMO `storeToRefs` just replaces one boilerplate with another, worse kind. Now you have to do ritual storeToRefs for all your refs (which ARE refs inside store's definition), and you have to explicitly separate state from methods every time you use the stuff (more cognitive complexity in exchange for nothing). I just don't get why pinia thinks it's a good idea to break defined refs with reactive object (which is bad with object destruction) and have more trouble instead of less. – Kazimir Podolski Aug 07 '23 at 18:33
  • Here's how I look at it: 1) `pinia` needs way less boilerplate than `vuex`. 2) a store's state is not exactly `ref`s, it's `reactive`. If you want the inner props of a `reactive` to remain reactive you either access them through the reactive container (in this case: `state.myProp`) or you have to convert them to refs, just like you do when you decompose a `reactive` for template `...toRefs(myContainer)`. Last, but not least, `pinia` was created because someone felt about `vuex` the way you feel about `pinia`. Maybe something even better will come out of your dissatisfaction with `pinia`. – tao Aug 08 '23 at 10:07