Vue3中ref可更新DOM但reactive无效的问题咨询
Vue3中reactive无法同步DOM更新的原因及解决方法
问题场景
使用ref时组件能正常渲染接口返回的数据,但用reactive时DOM完全没变化——两种情况控制台都能看到transaction有数据,这是为什么?此前的理解是「对象用reactive、基本类型用ref」,现在对二者的适用场景产生了困惑。
使用ref可正常运行的代码
<template> {{ transaction }} </template> <script setup> import { ref } from 'vue' let transaction = ref({}) const getPayByLinkTransaction = () => { axios({ method: "get", url: "pay-by-link", params: { merchantUuid: import.meta.env.VITE_MERCHANT_UUID, uuid: route.params.uuid, }, }) .then((res) => { transaction.value = res.data }) .catch((e) => { console.log(e) }) } getPayByLinkTransaction() </script>
使用reactive无法生效的代码
<template> {{ transaction }} </template> <script setup> import { reactive } from 'vue' let transaction = reactive({}) const getPayByLinkTransaction = () => { axios({ method: "get", url: "pay-by-link", params: { merchantUuid: import.meta.env.VITE_MERCHANT_UUID, uuid: route.params.uuid, }, }) .then((res) => { transaction = { ...res.data } }) .catch((e) => { console.log(e) }) } getPayByLinkTransaction() </script>
核心原因
reactive创建的响应式对象不能被直接替换:
ref本质是一个包装对象,你修改的是transaction.value,这个操作不会替换ref本身的引用,Vue能追踪到内部值的变化。reactive是把原始对象转换成响应式代理,当你执行transaction = { ...res.data }时,等于把原来的响应式代理直接换成了普通新对象——模板绑定的还是最初的空响应式对象,自然不会更新DOM。控制台能看到数据是因为变量被重新赋值,但这个变量已经和原来的响应式代理解绑了。
修正后的reactive写法
有两种可行的解决方式:
方式1:合并属性而非替换对象(推荐)
<template> {{ transaction }} </template> <script setup> import { reactive } from 'vue' const transaction = reactive({}) const getPayByLinkTransaction = () => { axios({ method: "get", url: "pay-by-link", params: { merchantUuid: import.meta.env.VITE_MERCHANT_UUID, uuid: route.params.uuid, }, }) .then((res) => { // 用Object.assign合并新属性到原有响应式对象 Object.assign(transaction, res.data) }) .catch((e) => { console.log(e) }) } getPayByLinkTransaction() </script>
方式2:用外层对象包裹,修改内层属性
<template> {{ transaction.data }} </template> <script setup> import { reactive } from 'vue' // 用reactive包装一个外层对象,内层存数据 const transaction = reactive({ data: {} }) const getPayByLinkTransaction = () => { axios({ method: "get", url: "pay-by-link", params: { merchantUuid: import.meta.env.VITE_MERCHANT_UUID, uuid: route.params.uuid, }, }) .then((res) => { // 修改内层属性,不会破坏外层的响应式代理引用 transaction.data = res.data }) .catch((e) => { console.log(e) }) } getPayByLinkTransaction() </script>
ref与reactive的适用场景补充
ref:不仅适用于基本类型,也适用于对象/数组。优势是可以直接通过.value替换整个值,在需要频繁重新赋值引用类型时更灵活。reactive:适用于复杂对象/数组,但必须保持对响应式代理的引用,只能修改内部属性。如果业务中需要频繁替换整个对象,用ref会更省心。
内容的提问来源于stack exchange,提问作者Dally
相关产品推荐
相关产品推荐

