vue3中的ref、computed、reactive、toRefs

Vue3中的响应式处理与Vue2有所不同,setup函数不再能直接获取到this。本文详细介绍了ref、computed、reactive和toRefs的用法。ref用于创建响应式的基本对象,computed用于计算属性,reactive用于创建响应式对象,而toRefs则用于将reactive对象转换为响应式属性。通过这些函数,开发者可以在Vue3中实现数据的响应式更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在vue2中,data函数里返回的值直接为响应式的,但在vue3中我们需要使用一些函数才能达到这个效果。

setup函数中拿不到vue的this

1、ref 

本质为一个函数,输入参数为一个值(原始类型),返回响应式的对象

2、computed

本质为一个函数,输入参数是一个函数,可以将我们需要的值作为输入函数的返回值

例子:实现点击按钮,屏幕上的数加1

<template>
  <div id='app'>
    <img alt="vue logo" src="./assets/logo.png">
    <!-- ref对象在模板中引用时,vue可以直接把内部的值展示出来,不需要写count.value -->
    <h1>{{count}}</h1>
    <h1>{{double}}</h1>
    <button @click='increase'>点击</button>
  </div>
</template>

<script lang='ts'>
//ref API:是一个函数,输入参数为一个值,返回一个响应式对象
//computed API:是一个函数,输入参数为函数类型,该输入函数中包含咱们需要的值
//reactive:将响应式变量包裹在一起,更加清晰
import {computed, ref,reactive} from 'vue'

export default({
  name: 'App', 

  /*data(){
    return{
      count: 0
    }
  },

  methods:{
    increase(){
      this.count++
    }
  }*/

  // 注意:在vue3中不使用data和methods,可以使用ref函数,完成响应式
  setup(){
    const count = ref(0)    //将0传入,返回一个对象

    const double = computed(()=>{
      return count.value*2
    })
    const increase = ()=>{
      count.value++         //通过返回对象的value属性获得响应式的数据
    }
    return{                 //要在外面使用的变量都要先通过return导出,才能使用
      count,
      increase,
      double
    }
  }
});
</script>

3、reactive

本质为一个函数,接受一个object作为传入参数

上述代码在setup函数中,有很多响应式数据,它们都是分散的,我们可以使用reactive将它们都包裹起来。输出对象类型,模板中需要用data.属性取出来。

<template>
  <div id='app'>
    <img alt="vue logo" src="./assets/logo.png">
    <h1>{{data.count}}</h1>
    <h1>{{data.double}}</h1>
    <button @click='data.increase'>点击</button>
  </div>
</template>

<script lang='ts'>

import {computed, ref,reactive} from 'vue'

export default({
  name: 'App', 

  // 注意:在vue3中不使用data和methods,可以使用ref函数,完成响应式
  setup(){
    const data = reactive({
      count:0,
      increase:()=>{
        data.count++
      },
      double:computed(()=>
        data.count*2
      )
    })
    return{                 //要在外面使用的变量都要先通过return导出,才能使用
      data
    }
  }
});
</script>

上述代码在运行时会报错,data数据类型会出错,这是因为内部的computed函数造成的data类型推论循环,需要解决。可以手动设置一个数据类型赋给data。

interface dataProps{
  count:number,
  double:number,
  increase:()=>void
}

继续修改上述代码,发现模板中每次使用数据都需要data.属性才能取出来,能不能直接用属性?这时我们想到了es6的...展开符,但是更改后发现点击按钮,屏幕上的数字不发生变化了,数据不是响应式的了。

这是因为这种方式返回的数据都是普通的js数据类型,并不是响应式的ref数据类型,因此我们需要新的方法。

4、toRefs

本质为一个函数,接受一个reactive函数作为输入参数,返回一个ref类型的对象。

<template>
  <div id='app'>
    <img alt="vue logo" src="./assets/logo.png">
    <!-- ref对象在模板中引用时,vue可以直接把内部的值展示出来,不需要写count.value -->
    <h1>{{count}}</h1>
    <h1>{{double}}</h1>
    <button @click='increase'>点击</button>
  </div>
</template>


const refData = toRefs(data)

return{                 //要在外面使用的变量都要先通过return导出,才能使用
  ...refData
}

这时,我们展开refData,就能实现响应式了。

### Vue3 中 `ref` 和 `reactive` 函数通过 Proxy 实现数据响应式解构 #### 一、`ref` 和 `reactive` 的工作原理 Vue 3 利用了 JavaScript 的新特性——Proxy 来实现响应式系统。无论是 `ref` 还是 `reactive` 创建的数据,内部都会被转化为带有拦截器的代理对象。 对于 `ref`,它主要用于包裹单个值(包括但不限于基础类型的数值),并将其转换为一个具有 `.value` 属性的对象实例来保持其自身的响应性[^2]: ```javascript import { ref } from &#39;vue&#39;; const count = ref(0); console.log(count.value); // 输出:0 count.value++; console.log(count.value); // 输出:1 ``` 而对于 `reactive`,则是针对复杂的嵌套结构如对象或数组进行深层次的响应化处理,使其每一个层次上的键都能独立触发 UI 更新机制[^4]: ```javascript import { reactive } from &#39;vue&#39;; let person = reactive({ firstName: "John", lastName: "Doe" }); person.firstName = "Jane"; // 当firstName改变时,视图会相应更新 ``` #### 二、解构导致失去响应性的现象及其解决方案 当直接对由 `reactive` 构建出来的对象执行 ES6 解构操作时,默认情况下所得到的新变量不再是响应式的副本而是普通的静态拷贝,这意味着后续对该变量所做的任何更改都不会引起界面重绘行为[^5]。 为了克服这个问题,官方提供了两个辅助工具函数 `toRefs()` 和 `toRef()` ,它们能够帮助我们将原本属于 `reactive` 定义下的属性逐个转变为具备相同特性的 `ref` 类型实体,从而确保即使是在外部环境中进行了拆分也不会破坏原有的观察者链条关系[^3]。 下面是一个具体的例子展示如何正确地运用这些概念来进行组件间的通信以及状态管理: ```typescript <template> <div>{{ fullName }}</div> <!-- 此处显示的是响应式的fullName --> </template> <script lang="ts"> import { defineComponent, reactive, computed, toRefs } from &#39;vue&#39;; export default defineComponent({ setup() { const userState = reactive({ first_name: &#39;Alice&#39;, last_name: &#39;Smith&#39; }); // 计算属性也支持作为响应式源的一部分参与进来 const fullName = computed(() => `${userState.first_name} ${userState.last_name}`); // 使用toRefs防止解构后丢失响应性 return { ...toRefs(userState), fullName, }; } }) </script> ``` 在这个案例里,不仅原始的状态字段可以通过解构的方式安全传递给模板层使用而不必担心丧失监听能力,而且还可以轻松加入其他形式的派生计算结果一同暴露出去供外界调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值