vue3.x之ref和reactive函数

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

定义响应式数据

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

1. ref

使用方法

⏰ 定义基本类型数据

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

<script lang="ts">
//👀:需要什么导入什么
import { ref } from 'vue'
export default {
  name: 'App',
  //setup函数是组合式API的入口函数,调用在beforeCreated之前
  setup() {
    //1.定义响应式变量
    const school = ref('高级中学');
    console.log('school',school);
    //2.定义函数
    const updateInfo = ()=>{
      school.value = '附属中学'
      console.log('school',school);
    } 
    //3.将相关属性,函数,暴露给外界方便使用
    return { school, updateInfo }
  }
}
</script>

效果如下:

 

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

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

⏰定义复杂类型数据

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

<script lang="ts">
//👀:需要什么导入什么
import { ref } from 'vue'
export default {
  name: 'App',
  //setup函数是组合式API的入口函数,调用在beforeCreated之前
  setup() {
    //1.定义响应式变量
    const person = ref({
      name:'艾薇儿',
      age:18,
      friend:{
        name:'安妮.海瑟薇',
        age:'28'
      },
      hobbies: ['music', 'dance', 'movie']
    })
    console.log('person',person);
    //2.定义函数
    const updateInfo = ()=>{
      person.value.friend.name = '王麻子';
      person.value = {
        name:'张赖子',
        age:25,
        friend:{
          name:'疯驴子',
          age:'28'
        },
        hobbies:['music','dance','movie']
      }
      console.log('person',person);
    } 
    //3.将相关属性,函数,暴露给外界方便使用
    return { person, updateInfo }
  }
}
</script>

效果如下:

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

修改对象值后效果如下:

使用场景

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

2. reactive

使用方法

⏰定义复杂类型数据

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

<script lang="ts">

//👀:需要什么导入什么
import { reactive } from 'vue'

export default {
  name: 'App',
  //setup函数是组合式API的入口函数,调用在beforeCreated之前
  setup() {
    //1.定义响应式变量
    let person = reactive({
      name: '艾薇儿',
      age: 18,
      friend: {
        name: '安妮.海瑟薇',
        age: '28'
      },
      hobbies: ['music', 'dance', 'movie']
    })
    console.log('person', person);

    //2.定义函数
    const updateInfo = () => {
      person = {
        name: '疯驴子',
        age: 25,
        friend: {
          name: '高启强',
          age: '28'
        },
        hobbies: ['music', 'dance', 'movie']
      }
      console.log('person', person);
    }

    //3.将相关属性,函数,暴露给外界方便使用
    return { person, updateInfo }
  }
}
</script>

效果如下:

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

效果如下:

如果修改对象的属性,那么视图是会及时更新的。

响应式会失效的情况

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

⏰ 重新赋值

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

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

给对象添加一个属性

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

<script lang="ts">
//👀:需要什么导入什么
import { reactive } from 'vue'
export default {
  name: 'App',
  //setup函数是组合式API的入口函数,调用在beforeCreated之前
  setup() {
    //1.定义响应式变量
    let person = reactive({
      data: {
        name: '艾薇儿',
        age: 18,
        friend: {
          name: '安妮.海瑟薇',
          age: '28'
        },
        hobbies: ['music', 'dance', 'movie']
      }
    })
    console.log('person', person);
    //2.定义函数
    const updateInfo = () => {
      person.data = {
        name: '疯驴子',
        age: 25,
        friend: {
          name: '高启强',
          age: '28'
        },
        hobbies: ['music', 'dance', 'movie']
      }
      console.log('person', person);
    }
    //3.将相关属性,函数,暴露给外界方便使用
    return { person, updateInfo }
  }
}
</script>

效果如下:

修改之后效果如下:

使用Object.assign()

⏰ 解构

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

<script lang="ts">
//👀:需要什么导入什么
import { reactive } from 'vue'

export default {
  name: 'App',
  //setup函数是组合式API的入口函数,调用在beforeCreated之前
  setup() {
    //1.定义响应式变量
    let person = reactive({
      name: '艾薇儿',
      age: 18,
      friend: {
        name: '安妮.海瑟薇',
        age: '28'
      },
      hobbies: ['music', 'dance', 'movie']
    })
    const { name, age, friend, hobbies } = person;
    console.log('person', person);
    //2.定义函数
    const updateInfo = () => {
      person.name = '疯驴子'
      console.log('person', person);
    }
    //3.将相关属性,函数,暴露给外界方便使用
    return { person, updateInfo, name, age, friend, hobbies }
  }
}
</script>

效果如下:

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

使用场景

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

posted on 2024-07-11 17:27  梁飞宇  阅读(50)  评论(0)    收藏  举报