Я сохраняю аутентифицированного пользователя своего веб-приложения (Vue и Supabase) в магазине Pinia: userStore.user. Мой компонент NavBar имеет ссылку для входа/выхода на основе этого состояния. Чтобы сделать это реактивным в моей NavBar, мне нужно создать user вычисляемое свойство: const user = computed(() => userStore.user).
Почему user в моей навигационной панели должно быть вычисляемым свойством? Я думал, что это будет реактивно, просто указав на пользователя в userStore, поскольку это реактивно в магазине Pinia. Кроме того, обертывание его в ссылку не сделало его реактивным. Я новичок в Vue и Pinia, и мне явно не хватает какой-то ключевой концепции.
Вот мой код в контексте:
// UserStore.js
import { defineStore } from 'pinia'
import { supabase } from '@/supabase'
export const useUserStore = defineStore('user', {
state: () => ({
user: null,
isLoggingIn: false,
isLoggingOut: false
}),
actions: {
async fetchUser() {
const {
data: { session }
} = await supabase.auth.getSession()
this.user = session?.user || null
},
async login(email, password) {
this.isLoggingIn = true
try {
const { user, error } = await supabase.auth.signInWithPassword({ email, password })
if (error) throw error
this.user = user
} finally {
this.isLoggingIn = false
}
},
async logout() {
this.isLoggingOut = true
try {
await supabase.auth.signOut()
this.user = null
} finally {
this.isLoggingOut = false
}
},
setUser(user) {
this.user = user
}
}
})
// NavBar.vue
<template>
<nav>
<router-link to = "/">Home</router-link> |
<router-link to = "/restricted">Restricted</router-link> |
<router-link v-if = "!user" to = "/login">Login</router-link>
<button v-else @click = "logout" :disabled = "isLoggingOut">
{{ isLoggingOut ? 'Logging out ...' : 'Logout' }}
</button>
</nav>
</template>
<script setup>
import { computed, ref } from 'vue'
import { useUserStore } from '@/stores/UserStore'
const userStore = useUserStore()
// const user = userStore.user // Not reactive to changes in userStore - why?
// const user = ref(userStore.user) // Also not reactive - why?
const user = computed(() => userStore.user) // This works
const isLoggingOut = computed(() => userStore.isLoggingOut)
const logout = userStore.logout
</script>
@kissu Геттер не будет служить хорошей цели, потому что он будет иметь ту же структуру, что и «пользователь», и вести себя так же при деструктуризации.





Невозможно поддерживать реактивность в JavaScript.
Вот что здесь происходит:
const foo = { bar: { baz: 'baz' } };
const barCopy = foo.bar;
foo.bar = { qux: 'qux' };
console.info(barCopy) // baz: 'baz'Это могло бы сработать, если бы существующий объект user никогда не переназначался, а вместо этого были изменены его свойства, но в вашем случае он полностью переназначен, что вполне разумно; это не предмет, а null изначально.
Чтобы поддерживать реактивность, его следует последовательно использовать как userStore.user для сохранения ссылки, включая использование его внутри computed. Помощник Пинии позволяет создавать записываемые данные, вычисляемые менее подробно:
const { user } = storeToRefs(userStore);
Спасибо! Вот соответствующий раздел в документации.
Потому что нам нужен геттер , как описано в документации. В основном это ярлык, который мы используем с ES6, чтобы сделать его короче. Я думаю, это правильный путь, потому что Vue использует прокси, и нам нужно оценить их в вычислении, а не просто передать ему переменную. Не эксперт в этом, больше людей могут дать подробную информацию.