Vue3,什么情况下数据会丢失响应式呢?

一、使用 reactive 定义的数据重新赋值
<template>
  <h1>{
    
    {
    
     foo.a }}</h1>
  <h1>{
    
    {
    
     bar.a }}</h1>
  <button @click="handleClick">点我</button>
</template>
<script setup>
import {
    
      ref, reactive } from 'vue'

let foo = ref({
    
     a: 1, b: 2, c: 3 })
let bar= reactive({
    
     a: 1, b: 2, c: 3 })

const handleClick = () => {
    
    
  foo.value = {
    
    
    a: 11
  }
  bar= {
    
    
    a: 99
  } 
}
</script>

原因: 为什么 ref 定义对象重新赋值后不会丢失响应式,而 reactive 会丢失响应式

结论:ref 定义对象重新赋值后不会丢失响应式,而 reactive 会丢失响应式。

二、响应式数据被解构赋值(大多是 props 中的数据被解构赋值)
<template>
  <h1>{
    
    {
    
     a.b.c }}</h1>
  <h1 v-if="a.b.d">{
    
    {
    
     a.b.d }}</h1>
  <h1>{
    
    {
    
     aa.bb }}</h1>
  <h1>{
    
    {
    
     aaa }}</h1>
</template>
<script setup>
import {
    
     ref, onMounted} from 'vue'
const obj = {
    
    
  a: {
    
    
    b: {
    
    
      c: 1
    }
  },
  aa: {
    
    
    bb: 11
  },
  aaa: 111
}
let testObj = ref(obj)
let {
    
     a, aa, aaa } = testObj.value

onMounted(() => {
    
    
  setTimeout(() => {
    
    
    a.b.c = 9
    a.b.d = 9
    aa.bb = 99
    aaa = 999
  }, 3000)
})
</script>

上列数据只有 aaa 丢失了响应式

原因:

我们知道解构赋值,区分原始类型的赋值,和引用类型的赋值,原始类型的赋值相当于按值传递,引用类型的值就相当于按引用传递

按值传递

 // 假设a是个响应式对象
	a.b = 1
 // c 此时就是一个值跟当前的 a 已经不沾边了
	const c=a.b // 相当于 c = 1

你直接访问 c 就相当于直接访问这个值,也就绕过了 a 对象的 getter。所以最开始的例子中,aaa 失去了响应式

按引用传递

 // 假设 a 是个响应式对象
 const a.b.c = 3
 // 当你访问a.b的时候就已经重新初始化响应式了,此时的 c 就已经是一个代理的对象
 const c=a.b

你直接访问 c 就相当于访问一个响应式对象,所以并不会失去响应式

为什么 a.b 是响应式的呢?

源码中 reactive 方法调用了 createReactiveObject 方法,createReactiveObject 方法中,有一个判断,来检查数据是否是响应式的

// target already has corresponding Proxy
    const existingProxy = proxyMap.get(target);
    if (existingProxy) {
    
    
        return existingProxy;
    }

注释表明了这个 if 的作用是,判断目标对象是否是响应式,如果是则返回,所以 c 得到的还是响应式的数据

结论:对响应式数据进行解构赋值,如果解构出来的数据是 基本数据类型,则会丢失响应式,如果是 引用类型,则不会丢失响应式。

三、使用vuex的数据进行赋值
<template>
  <h1>{
    
    {
    
     test }}</h1>
  <h1>{
    
    {
    
     testCom }}</h1>
</template>
<script setup>
import {
    
     ref, onMounted, computed } from 'vue'
import {
    
     useStore } from 'vuex'
const store = useStore()
// store.state.testData的初始值为 '11111'
let test = ref(store.state.testData) // 相当于let test = ref('11111')
// 解决办法
let testCom = computed(() => {
    
    
  return store.state.testData
}) 

onMounted(() => {
    
    
  setTimeout(() => {
    
    
    store.commit('getTestData', '12345')
  }, 3000)
})
</script>

原因: 还是变量赋值的原因,就不赘述了

解决办法: 使用 computed

猜你喜欢

转载自blog.csdn.net/weixin_46683645/article/details/125977313