如何可靠地将一些Pinia状态转换为本地组件状态



在我的next应用程序中,我有一个页面来编辑用户配置文件,这是保存在piia商店中的数据。以下是该商店的基本内容:

import { defineStore } from 'pinia'
import { Database } from '~~/types/supabase'
interface Profile {
id: string
important_field: number | null
}
interface State {
profile: Profile | null
}
export const useStore = defineStore('main', {
state: (): State => {
return {
profile: null
}
},
actions: {
async getProfile() {
const { data: profile, error } = await useSupabaseClient<Database>().from('profiles').select().limit(1).single()
if (profile) {
this.profile = profile
}
},
async updateProfile(profile: Profile) {
this.profile = profile
const { error } = await useSupabaseClient<Database>()
.from('profiles')
.update(profile)
.eq('id', profile.id)
}
},
})

app.vue被启动时,getProfile方法被调用。

现在,当我转到/profile页面时,我不想能够反应性地调整important_field。顾名思义,该字段对应用程序的其他功能很重要,所以我希望用户能够调整它,然后点击保存按钮将其存储回Pinia。

要做到这一点,我认为我可以将配置文件状态复制到配置文件页面组件中的本地响应变量中,对其进行修改,然后将其发送回商店的updateProfile方法:
const store = useStore()
const profile = reactive({...store.profile})

然而,当我加载/profiles页面时,问题出现了,Pinia还没有安装,所以store.profile是空的,我的本地profile变量从未获得从服务器获取的数据,并更新到Pinia存储。即使在onMounted中放入上述内容也不起作用:组件在安装Pinia之前安装,因此本地配置文件变量保持为"空白"。

我已经拼凑了一个解决方案,可以工作,但它很粗糙。

<script setup lang="ts">
import { useStore } from '~~/stores'
import { Database } from '~~/types/supabase'
type Profile = Database['public']['Tables']['profiles']['Row']
const store = useStore()
const profile: Profile = reactive({ id: '', important_field: 0 })
store.$subscribe((mutation, state) => {
if (profile.id === '' && state.profile !== null) {
profile.id = state.profile.id
profile.important_field = state.profile.important_field
}
})
</script>
<template>
<div>
Profile
<div v-if="profile">
<label for="">
Important Field
<input type="number" v-model="profile.important_field">
</label>
</div>
<button @click="store.updateProfile(profile)">Save</button>
<br>
</div>
</template>

这看起来很笨拙,我觉得我缺少一个更好的方法来做到这一点。

是否有更好的解决方案从Pinia商店抓取状态,本地调整它,然后将其发送回商店?

在没有Pinia的情况下使用已经内置在变量状态管理中的next解决问题useState():

<script setup lang="ts">
const { data: profile, error } = await useSupabaseClient<Database>().from('profiles').select().limit(1).single()
const profileData = reactive({...profile})
useState('profile', () => profile) // Assigning variable to global variable state management already inside Nuxt. No need any Pinia!
</script>

保存数据:

<script setup lang="ts">
// Getting global variable to local, so you can change it without changing original one.
const profile = toReactive(useState('profile'))
function update() {
useSupabaseClient<Database>()
.from('profiles')
.update(profile)
.eq('id', profile.id)
useState('profile').value = profile
}
</script>

useState()工作在服务器端和客户端。如果需要一些用户凭据来获取用户数据。在:<ClientOnly><UserProfile></UserProfile></ClientOnly>中包装组件,这样组件只会在客户端呈现,不会有问题。

最新更新