vue3定义响应式数据之ref和reactive

1,912 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第10天,点击查看活动详情

在vue2中定义数据在模板中使用的时候,只要不是那几种特殊情况,正常定义数据都是响应式的,但是在vue3中是不一样的,如果直接用=定义数据变量是不具有响应式的。

定义响应式数据

在使用ref和reactive定义响应式数据的时候,它们的使用场景是不一样的。

1. ref

1.1 使用方法

定义基本类型数据

<div>{{school}}学生信息</div>
<button @click="updateInfo">修改信息</button>

import { ref } from 'vue';
const school = ref('高级中学');

console.log('school', school);
const updateInfo = () => {
  school.value = '附属中学';
  console.log('school', school);
}

效果如下:

1676197315662.png 可以看出ref就是将基础数据转换为响应式数据,把数据包装成响应式的引用数据类型的数据。

修改ref定义的值需要使用.value去操作,效果如下:

1676197529572.png

定义复杂类型数据

<div>姓名:{{person.name}}</div>
<div>年龄:{{person.age}}</div>
<div>朋友:{{person.friend.name}}-{{person.friend.age}}</div>
<div v-for="(item, index) in person.hobbies" :key="index">爱好列表
  <div>{{item}}</div>
</div>
<button @click="updateInfo">修改信息</button>

import { ref } from 'vue';
const person = ref({
  name: '艾薇儿',
  age: 18,
  friend: {
    name: '安妮·海瑟薇',
    age: '28'
  },
  hobbies: ['music', 'dance', 'movie']
})
console.log('person', person);
const updateInfo = () => {
  person.value.friend.name = '麻子';
  person.value = {
    name: '疯驴子',
    age: 25,
    friend: {
      name: '高启强',
      age: '28'
    },
    hobbies: ['music', 'dance', 'movie']
  }
  console.log('person', person);
}

效果如下:

image.png

可以看出使用ref定于复杂类型数据时是会将复杂类型对象使用Proxy转成响应式对象的,但是对于响应式对象我们不建议使用ref,应该有一个更适合的方式就是下面介绍的reactive。

修改对象值后效果如下:

1676198041618.png

1.2 使用场景

  1. 用来定义基本数据类型
  2. 在修改值和获取值的时候需要使用.value,在模板中是不需要使用.value

2. reactive

2.1 使用方法

<div>姓名:{{person.name}}</div>
<div>年龄:{{person.age}}</div>
<div>朋友:{{person.friend.name}}-{{person.friend.age}}</div>
<div v-for="(item, index) in person.hobbies" :key="index">爱好列表
  <div>{{item}}</div>
</div>
<button @click="updateInfo">修改信息</button>

import { reactive } from 'vue';
let person = reactive({
  name: '艾薇儿',
  age: 18,
  friend: {
    name: '安妮·海瑟薇',
    age: '28'
  },
  hobbies: ['music', 'dance', 'movie']
})
console.log('person', person);
const updateInfo = () => {
  person = {
    name: '疯驴子',
    age: 25,
    friend: {
      name: '高启强',
      age: '28'
    },
    hobbies: ['music', 'dance', 'movie']
  }
  console.log('person', person);
}

效果如下:

image.png

从上述效果图我们可以看出,使用reactive定义的数据会转成响应式对象(proxy)。但是如果直接修改这个对象响应式是会失效的,即使数据内容变量,视图也不会更新。如果修改对象的属性,那么视图是会及时更新的。

效果如下:

image.png

2.2 响应式会失效的情况

像上述对对象直接赋值,响应式是会生效的。除了直接赋值之外,响应式还会生效有以下几种情况:

2.2.1 重新赋值

上述针对复杂类型的数据,如果重新赋值的话,相当于是将变量的引用指向了另外一个地址,而这个地址对象是新加的,没有通过reactive进行代理,所以不具有响应式。

针对上述情况,可以通过以下方法使其继续变成响应式数据。

给对象添加一个属性

<div>姓名:{{person.data.name}}</div>
<div>年龄:{{person.data.age}}</div>
<div>朋友:{{person.data.friend.name}}-{{person.data.friend.age}}</div>
<div v-for="(item, index) in person.data.hobbies" :key="index">爱好列表
  <div>{{item}}</div>
</div>
<button @click="updateInfo">修改信息</button>

import { reactive } from 'vue';
let person = reactive({
  data: {
    name: '艾薇儿',
    age: 18,
    friend: {
      name: '安妮·海瑟薇',
      age: '28'
    },
    hobbies: ['music', 'dance', 'movie']
  }
})
console.log('person', person);
const updateInfo = () => {
  person.data = {
    name: '疯驴子',
    age: 25,
    friend: {
      name: '高启强',
      age: '28'
    },
    hobbies: ['music', 'dance', 'movie']
  }
  console.log('person', person);
}

初始效果如下:

image.png

修改之后效果如下:

image.png

使用Object.assign()

2.2.2 解构

<div>姓名:{{name}}</div>
<div>年龄:{{age}}</div>
<div>朋友:{{friend.name}}-{{friend.age}}</div>
<div v-for="(item, index) in hobbies" :key="index">爱好列表
  <div>{{item}}</div>
</div>
<button @click="updateInfo">修改信息</button>

import { reactive } from 'vue';
let person = reactive({
  name: '艾薇儿',
  age: 18,
  friend: {
    name: '安妮·海瑟薇',
    age: '28'
  },
  hobbies: ['music', 'dance', 'movie']
});
const { name, age, friend, hobbies} = person;
console.log('person', person);
const updateInfo = () => {
  person.name = '疯驴子';
  console.log('person', person);
}

效果如下:

image.png

从上述效果图中可以看出解构赋值后失去了响应式。解构赋值中对于基本数据类型是按值传递,对于引用类型是按引用传递。name虽然是person.name的值,但是访问name的时候绕过了对象的get方法,因此失去了响应式,如果是按引用类型来传递的话就不会失去响应式。

2.2 使用场景

  1. 用来定义复杂数据类型
  2. 定义数组的时候需要