vue3 还不知道怎么选ref和reactive,还不赶快进来

5,250 阅读3分钟

🕒携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1

来自网友的的指正,这是第次修改


Vue 3 的 Composition API 提供了两种主要的方式来声明响应式数据:refreactive

✏️ 这些有什么区别?

✏️ 实际项目中如何合理选择?


1.是什么ref

官方的解释是这样的

image.png

看个例子:

<template>
  <div>数值类型:{{number}}</div>
</template>

<script>
import { ref } from 'vue'
export default {
  setup () {
    let number = ref(0)
    console.log('ref对象', number)
    console.log('取值', number.value)
    return {
      number
    }
  }
}
</script>

我这分别把ref对象和值打印出来了,看看返回的响应式对象到底啥样

image.png

❗️新手的易错点:

一个很大的“陷阱”, ref是在 JavaScript 中访问值与在模板中访问它是不同的

🍓模板
<h1>{{ number.value }}</h1> <!--❌-->
<h1>{{ number }}</h1> <!--✔️-->

🍑js
<script>
import { ref } from 'vue'
export default {
  setup () {
    let number = ref(0)
    console.log('取值', number.value)<!--❗️取值需要.value❗️-->
    return {
      number
    }
  }
}
</script>

❓提问环节:

1.可以接受的值有哪些?

答: 基本数据类型和对象类型

2.基本数据类型怎么实现响应式?

答: 依靠Object.defineProperty()getset完成

3.对象类型怎么实现响应式?

答: 内部求助了vue3一个新的函数叫reactive函数

2. 是什么reactive

官方解释:

image.png

<template>
  <div>姓名:{{obj.name}}</div>
  <div>年龄:{{obj.age}}</div>
</template>

<script>
import { reactive } from 'vue'
export default {
  setup () {
    let obj = reactive({
      name: '葱头',
      age: 28
    })
    console.log('reactive对象', obj)
    console.log('取值', obj.name)
    return {
      obj
    }
  }
}
</script>

我这分别把reactive对象和值打印出来了,看看返回的响应式对象到底啥样 image.png

❗️新手的易错点:

最大的“陷阱”reactive可能会诱使您解构对象,尤其是当它是从另一个文件中的函数返回时

<template>
  <div>姓名:{{obj.name}}</div>
  <div>年龄:{{obj.age}}</div>
</template>

<script>
import { reactive } from 'vue'
export default {
  setup () {
    let obj = reactive({
      name: '葱头',
      age: 28
    })
    let { age } = obj
    console.log(age)
    age++
    console.log(age)
    return {
      obj
    }
  }
}
</script>

image.png

响应式丢失了 ❗️ ❗️ ❗️ ,那我这个怎么写?,往下看

<template>
  <div>姓名:{{obj.name}}</div>
  <div>年龄:{{obj.age}}</div>
</template>

<script>
import { reactive } from 'vue'
export default {
  setup () {
    let obj = reactive({
      name: '葱头',
      age: 28
    })
    obj.age++
    return {
      obj
    }
  }
}
</script>

image.png

❓提问环节:有的小伙伴说为啥?

我们分析一下:

首先看一下log,我们发现这个返回的响应式对象为什么没有变化,我明明+1了呀

image.png

我给大家看一下原因

 let { age } = obj
 age++
 实际是这样的
 let duixing={
      name: '葱头',
      age: 28
    }
   duixing.age++ 
   你操作的不是响应式的对象,你操作的是{name: '葱头',age: 28}中的age变量,
   人家响应式是这样的 Proxy {name: '葱头', age: 28},所以解构会失去响应式!!!

前端小菜鸡之青岛分鸡同学反馈看不懂上面的,那我一起看看下面代码

const obj1 = {
age: 28
}
const handler = {
get: function (target, key) {
console.log('get--', key)
return Reflect.get(...arguments)
},
set: function (target, key, value) {
console.log('set--', key, '=', value)
return Reflect.set(...arguments)
}
}
const data = new Proxy(obj1, handler)
// 这种方法是错误的,不能解构
let { age } = data
age++
console.log(age, '错误age')
console.log(data, '错误data')
console.log(data.age, '错误data.age')
// 正确的方法是这样些的
data.age++
console.log(age, '正确的age')
console.log(data, '正确的data')
console.log(data.age, '正确的data.age')

image.png

下面是夏2同学提出的,让我增加建议补充下reactive的响应式版本的解构,安排

❓toRefs 是什么?

toRefs可以将对象(只能接收rective对象)中的属性变成响应式,正常reactive对象数据也是响应式的,如果用toRefs解构出去会更加方便

❓什么时候用?

数据量如果很多, 我们一般会用解构来简化代码, 那么在vue3 中如果使用对象的解构, 会让改对象失去响应式, 所有一般解构的时候 借助 toRefs 来解构 仍然带有响应式解构后, 我们就不需要用对象属性了, 而是可以直接使用属性,来简化 看一下例子

image.png

<script setup>
import { reactive,toRefs } from 'vue'

const obj = reactive({
  name:'给葱头点个赞吧,谢谢小哥哥小姐姐啦',
  age:'27'
})
const {name}  = toRefs(obj)
</script>

<template>
  <h1>{{ name }}</h1>
  <input v-model="name"> 
</template>

image.png

3.应该使用reforreactive

1.首先看一下各自的优点?

ref优点:

  • 适合传递单个变量
  • 避免解构陷阱

reactive优点:

  • 适合声明大量反应变量
  • JavaScript 和模板之间的一致性
  • 跟 Vue 2 的数据对象很相似

2.讲了这么多,到底用啥?

在开发一个项目的时候最好选择一个,通常选择ref,因为它更灵活,看我们之前的图片可见ref不光能处理常见的数据类型,处理对象可以求助reactive函数,简直万能,直接给我盲选!!!

image.png