Vue中重新赋值ref后丢失响应性?原因及解决方法
Vue组件loading状态更新异常问题排查与修复
问题代码
组件代码(简化版)
<template> <div @click="loadEvents">{{ loading }}</div> </template> <script setup> import { ref } from 'vue' let loading = ref(false) loadEvents() function loadEvents() { const res = backendApi.getEvents(selectedDate.value) loading = ref(res.loading) } </script>
backendApi.getEvents方法代码
getEvents() { const loading = ref(true) axios.get(...).then(r => loading.value = false) return { loading } }
问题分析
- 首次加载正常,点击后无更新:首次调用
loadEvents时,组件的loading变量绑定的是初始创建的ref,后端返回的ref变化能通过初始关联同步到DOM。但点击触发loadEvents时,执行loading = ref(res.loading)相当于把组件的loading变量替换成了一个新的ref对象,而模板绑定的还是最初的那个ref,新ref的状态变化无法触发DOM更新。 - 赋值
loading.value = res.loading.value仅生效一次:这种写法只是把后端loading当前的true值拷贝到组件的loading里,两者没有建立响应式关联。当后端请求完成把loading.value改为false时,组件的loading不会同步更新。
修复方案
方案一:监听后端loading状态同步到组件
通过watch监听后端返回的loading值,实时同步到组件的loading变量:
<template> <div @click="loadEvents">{{ loading }}</div> </template> <script setup> import { ref, watch } from 'vue' let loading = ref(false) loadEvents() function loadEvents() { const res = backendApi.getEvents(selectedDate.value) // 立即同步初始值,并监听后续变化 watch(res.loading, (newVal) => { loading.value = newVal }, { immediate: true }) } </script>
方案二:组件自行管理loading状态(更推荐)
放弃依赖后端返回的ref,组件内部手动控制loading状态,逻辑更清晰:
<template> <div @click="loadEvents">{{ loading }}</div> </template> <script setup> import { ref } from 'vue' let loading = ref(false) loadEvents() function loadEvents() { loading.value = true // 修改后端API,让它返回axios请求的Promise backendApi.getEvents(selectedDate.value) .then(() => { loading.value = false }) .catch(() => { loading.value = false // 异常场景也要重置loading }) } </script> // 对应的backendApi.getEvents修改: getEvents(date) { return axios.get(/* 请求地址和参数 */).then(r => r.data) }
内容的提问来源于stack exchange,提问作者Lukas
相关产品推荐
相关产品推荐

