为何reactive状态变更时,ref对象未同步更新?
问题描述
我在文件中定义了reactive状态对象,UI能随该对象变更正常更新,但添加PrimeVue菜单组件后,菜单项的visible属性无法随state.state.user.isSignedIn状态变化而更新。state是reactive类型,menuItems是ref类型,两者都是响应式对象,为什么UI不更新?目前只能通过watch监听状态来处理,这种方式不够优雅。
相关代码
State.ts
export const state: types.State = reactive( { journal: {entries:[], databaseSchemaVersion: 0}, user: {isSignedIn: false} });
Menu.vue
<!-- HTML ----------------------------------------------------- --> <template> <PVMenu ref="menu" id="overlay_menu" :model="menuItems" :popup="true" /> </template> <!-- JS ------------------------------------------------------- --> <script setup lang="ts"> const menu = ref(); const menuItems = ref([ { label: messages.Signout, icon: 'fa fa-right-from-bracket', visible: state.state.user.isSignedIn, // 无法更新 :( command: () => { state.setDropboxToken(''); } } ]); // 能用但不够优雅的写法 watch(() => state.state.user.isSignedIn, (newValue) => { menuItems.value.filter(item => item.label === messages.Signout)[0].visible = newValue; }); </script>
原因分析与解决方案
原因
初始化menuItems时,visible属性直接赋值为state.state.user.isSignedIn的当前值,并没有建立响应式依赖关系。虽然menuItems是ref数组,但数组内的对象是普通对象,visible只是静态值,无法自动追踪state的变化。
优化方案
方案1:使用计算属性生成菜单数组
将menuItems改为计算属性,每次state.state.user.isSignedIn变化时,计算属性会重新执行生成新的菜单配置,自动触发UI更新:
<script setup lang="ts"> import { computed } from 'vue'; const menu = ref(); const menuItems = computed(() => [ { label: messages.Signout, icon: 'fa fa-right-from-bracket', visible: state.state.user.isSignedIn, command: () => { state.setDropboxToken(''); } } ]); </script>
方案2:让菜单对象成为响应式对象
若不想用计算属性,可将菜单数组内的对象转为reactive,并通过getter建立响应式依赖:
<script setup lang="ts"> import { reactive } from 'vue'; const menu = ref(); const menuItems = ref([ reactive({ label: messages.Signout, icon: 'fa fa-right-from-bracket', get visible() { return state.state.user.isSignedIn; }, command: () => { state.setDropboxToken(''); } }) ]); </script>
方案1更推荐,计算属性天然适配这种依赖响应式状态生成数据的场景,代码简洁且符合Vue响应式设计思路。
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

