vue响应式API,ref和reactive的使用

什么是组合式API

组合式 API(Composition API)是一系列 API 的集合,使我们可以使用函数而不是声明选项的方式书写 Vue 组件。它是一个概括性的术语,涵盖了以下方面的 API:

在最新的vue中,vue采用了组合式API的风格来书写代码,vue官方展示了组合式API和选择式API的用法

选项式 API (Options API)​

使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 data、methods 和 mounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。

javascript 复制代码
<script>
export default {
  // data() 返回的属性将会成为响应式的状态
  // 并且暴露在 `this` 上
  data() {
    return {
      count: 0
    }
  },

  // methods 是一些用来更改状态与触发更新的函数
  // 它们可以在模板中作为事件处理器绑定
  methods: {
    increment() {
      this.count++
    }
  },

  // 生命周期钩子会在组件生命周期的各个不同阶段被调用
  // 例如这个函数就会在组件挂载完成后被调用
  mounted() {
    console.log(`The initial count is ${this.count}.`)
  }
}
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

组合式 API (Composition API)

通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup> 中的导入和顶层变量/函数都能够在模板中直接使用。

下面是使用了组合式 API 与 <script setup> 改造后和上面的模板完全一样的组件:

javascript 复制代码
<script setup>
import { ref, onMounted } from 'vue'

// 响应式状态
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
  count.value++
}

// 生命周期钩子
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

可以发现这两个代码书写方式的不同点在于组合式API的script标签多了一个setup属性,同时多了一个ref方法。

这里的setup属性其实是对setup函数的一个封装,它表示整个script标签的内容全部都属于setup函数,并自动返回响应式的值。

setup函数和script setup标签

setup函数

  • setup()函数返回值通常是一个对象,这个对象的所有属性会暴露给组件模板和组件实例
  • setup()函数中的this指向undefined
  • setup()函数会在所有生命周期函数beforeCreate之前被执行。
  • setup()函数内定义的变量默认为非响应式的,所以对外暴露该属性为非响应式
html 复制代码
<script>
  export default {
    // setup函数是所有组合式API的入口(表演的舞台)
    setup() {
      // .....所有代码在此书写
    },
  };
</script>

在setup函数中返回的对象属性,在整个组件中是直接可以被访问的,但是这些属性都是非响应性的,当改变属性的值时,页面并不会同步更新,非响应的值对组件来说相当于一个常量,无法改变 ,,那我们知道vue框架是一个动态可编辑的组件集合,这自然是需要能响应的值来保证其动态更新,这就需要使用响应式API来实现

什么是响应式API

在setup函数中,返回的值是不能够被改变的,通过响应式API(ref和reactive)的响应式代理,可以实现传递动态变化的值。

ref方法

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value

  • 可更改是指你可以为ref对象的value属性赋予新的值
  • 响应式是指所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用(DOM 更新)
html 复制代码
<script>
  import { ref } from "vue";
  export default {
    setup() {
      // msg为一个ref对象,并且是响应式的
      const msg = ref("Hello Vue!!"); // {value: "Hello Vue!!"}

      // 修改ref对象value属性的值
      msg.value = "Hello ref!!";

      return {
        msg,
      };
    },
  };
</script>
<template> {{ msg }} </template>

使用setup的script标签

html 复制代码
<script setup>
import { ref } from "vue";
  
// msg为一个ref对象,并且是响应式的
const msg = ref("Hello Vue!!"); // {value: "Hello Vue!!"}
// 修改ref对象value属性的值
msg.value = "Hello ref!!";

</script>
<template> {{ msg }} </template>

这里的msg其实就相当于一个对象他有一个属性value,值等于注入的值,例如,字符串,数字,对象,可以通过value属性来访问到这个值,

但是我们注意到,既然这个值是在value属性中存放的,在template标签又直接使用msg却打印出了值,这里是响应式对象会自动解包 ref 属性。

一个响应式对象的属性及嵌套属性的值如果为ref属性,在模板或setup()中使用时,会自动解包,同时保持响应性(msg = msg.value),但是,当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包。同时,在script标签内是不会解包的,任需要通过value来访问值。

reactive方法

reactive()方法用来返回一个对象的响应式代理(对象)。

javascript 复制代码
const objProxy = reactive(obj); // objProxy为obj对象的响应式代理
html 复制代码
<script>
  // 导入reactive方法
  import { reactive } from "vue";
  export default {
    setup() {
      const obj = { a: 1, b: 2 };
      // Info为响应式代理对象
      const objProxy = reactive(obj);
      console.log(objProxy); // Proxy(Object) {a: 1, b: 2}

      function update() {
        // 修改对象属性的值
        objProxy.a = 10;
        objProxy.b = 20;
      }
      // 将属性暴露给组件实例
      return {
        objProxy,
        update,
      };
    },
  };
</script>
<template>
  <div>a的值:{{ objProxy.a }}</div>
  <div>b的值:{{ objProxy.b }}</div>
  <button @click="update">更新a,b的值</button>
</template>

点击按钮后a,b的值改变并渲染到了页面上,这表示objProxy代理对象具有响应性,所以objProxy为响应式代理对象。

但是要注意reactive() 无法转换基本数据类型,

javascript 复制代码
const msg = reactive("Hello Vue!!");// error

这种用法会直接报错,reactive()方法只能将一个对象转换为一个响应式对象,而不能将一个基本数据类型转换为响应式对象。因为reactive()方法的底层采用的是Proxy来实现的,而Proxy只能创建对象的代理。Proxy对象可以参考: Proxy - JavaScript | MDN

正确的方式是使用ref

javascript 复制代码
const msg = ref("Hello Vue!!");// success

总结

响应式API可以让setup中的非响应数据,传递出来,并使其可以响应,从而实现页面的动态编辑,

我们可以把ref和reactive看成组件中对数据的特殊赋值,

javascript 复制代码
const num = ref(0); => let num = 0;
const obj = reactive({age:10}); => let obj = {name:10};

更多相关内容可以参考:

Vue 组合式 API - setup、reactive 与 ref,响应式工具 | arry老师的博客-艾编程 (arryblog.com)

响应式基础 | Vue.js (vuejs.org)

相关推荐
辻戋30 分钟前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保32 分钟前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun1 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp1 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.2 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl4 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫6 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友6 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理8 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻8 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js