Vue3-02-响应性 reactive

news2025/1/12 15:46:12

1. setup

setup 是一个组件选项,组合式 API 就定义在 setup 中,包括 data、methods、computed 和 watch 等,都定义在 setup 中。

setup 实际上是一个生命周期钩子函数,执行时间点相当于 Vue2 中 beforeCreate 和 created 的结合。

2. ref

ref 将传入参数的值包装为一个带 value 属性的 ref 对象,使用 value 属性来访问之前的值,ref 对象的 value 属性也是响应式的。

ref 对象被传递给函数或是从一般对象上被解构时,不会丢失响应性。

在模板中使用 ref 时可以省略 .value。

案例场景:一个计数器组件 Counter

<template>
  <div class="home">
    <h1>{{ count }}</h1>
    <h1>{{ double }}</h1>
    <button type="button" @click="increase">button</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, computed } from 'vue';

export default defineComponent({
  name: 'Counter',
  setup() {
    const count = ref(0);
    const double = computed(() => count.value * 2);
    const increase = () => { count.value++; };

    return {
      count,
      double,
      increase
    }
  }
});
</script>

为了更高效的打包代码,Vue3 中的所有模块,包括 ref 和 computed 都要进行引入。

上面这段代码还是有可优化空间的,因为我们发现,这些变量、方法和计算属性都是分散的。那我们有什么办法将这些元素都集中起来呢?就可以使用 reactive。

3. reactive

reactive 的作用是返回对象的响应式副本。响应式对象其实是 JavaScript Proxy,其行为表现与一般对象相似。不同之处在于 Vue 能够跟踪对响应式对象属性的访问与更改操作。

当我们调用 reactive 方法时,可以给它传递一个对象,最终返回的就是传入的对象的一个响应式副本。

reactive 有2条限制:

(1) 仅对对象类型有效(对象、数组和 Map、Set 这样的集合类型),而对 string、number 和 boolean 这样的 原始类型 无效。

(2) 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失。

同时这也意味着当我们将响应式对象的属性赋值或解构至本地变量时,或是将该属性传入一个函数时,我们会失去响应性。

对上面的代码使用 reactive 进行改造,如下:

setup() {
  const data = reactive({
    count: 0,
    double: computed(() => data.count * 2),
    increase: () => { data.count++; },
  });

  return {
    count: data.count,
    double: data.double,
    increase: data.increase
  }
}

 我们将上面的 count、double 和 increase 放入一个变量,然后使用 data 变量来接收 reactive 返回的对象副本,再将 data 暴露给模板。这样做看似没问题,但会出现如下报错:

表示变量 data 隐式的具有 any 类型,它没有类型批注等信息。这里报错的主要原因是因为我们没有定义变量 data 的类型,没有告诉 TS 编译器 data 应该包含哪些属性。

这里我们并没有享受到 TS 带来的好处,反而不能按写 JS 代码的方式来写 TS 代码了。解决方案为新定义一个接口 DataProps,然后将变量 data 的类型设置为 DataProps。

interface DataProps {
  count: number;
  double: number;
  increase: () => void;
}

setup() {
  const data: DataProps = reactive({
    count: 0,
    double: computed(() => data.count * 2),
    increase: () => { data.count++; },
  });

  return {
    count: data.count,
    double: data.double,
    increase: data.increase
  }
}

这次看似又好像没问题了,然后我们打开浏览器访问,发现点击按钮时页面上的数字并没有变。最主要的原因是因为当我们要把 data.count、data.double 和 data.increase 的值单独拿出来时,都会失去它们的响应性。

这里我们还需要用到 Vue 提供的另一个方法 toRefs。

4. toRefs

toRefs 方法的作用是将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref。

setup() {
  const data: DataProps = reactive({
    count: 0,
    double: computed(() => data.count * 2),
    increase: () => {
      data.count++;
    },
  });

  // toRefs
  const state = toRefs(data); // { count: ref(0), ... }

  return {
    count: state.count,
    double: state.double,
    increase: state.increase
  }
}

这时再打开浏览器访问,点击按钮页面上的数字就可以自增了。

这里还可以使用 ES 6 的剩余运算符和解构赋值进行代码优化:

const state = toRefs(data); // { count: ref(0), ... }

return {
  ...state
}

本文案例的完整代码如下:

<template>
  <div class="home">
    <h1>{{ count }}</h1>
    <h1>{{ double }}</h1>
    <button type="button" @click="increase">button</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, computed } from 'vue';

interface DataProps {
  count: number;
  double: number;
  increase: () => void;
}

export default defineComponent({
  name: 'Counter',
  setup() {
    const data: DataProps = reactive({
      count: 0,
      double: computed(() => data.count * 2),
      increase: () => { data.count++; },
    });

    // toRefs
    const state = toRefs(data); // { count: ref(0), ... }

    return {
      ...state
    }
  }
});
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/601929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springcloud-alibaba (03)Sentinel规则-笔记

sentinel Sentinel提供的各种规则的简单说明01&#xff0c;流量控制一&#xff0c;流控规则&#xff08;阈值类型&#xff1a;QPS&#xff09;二&#xff0c;流控规则&#xff08;阈值类型&#xff1a;并发线程数&#xff09;三&#xff0c;高级选项 02&#xff0c;熔断降级一&…

day45_项目

SQL /* 在分页查询中,有一些常见变量名 pageNo 当前页(页码),默认是1 pageSize 每页展示数据的条数,需求给定 pageCount 共多少页pageCounttotal%pageSize0?(total/pageSize):(total/pageSize)1; total 共多少条数据,select count(id)计算出 */ -- 假设,每页展示4条 …

LEAP软件操作基础/安装与注册/基本原理和数据结构

本次内容突出与实例结合&#xff0c;紧密结合国家能源统计制度及《省级温室气体排放编制指南》&#xff0c;深入浅出地介绍针对不同级别研究对象时如何根据数据结构、可获取性、研究目的&#xff0c;构建合适的能源生产、转换、消费、温室气体排放&#xff08;以碳排放为主&…

电力系统直流潮流计算研究【IEEE9节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

JavaEE初阶学习:网络原理

1.应用层 应用层和代码直接相关的一层 决定了数据要传输什么,拿到数据之后如何使用 约定应用层数据报,数据格式,就是在自定义协议~~ 如何约定? 1.确定要传输那些信息,(根据需求走的) 外卖程序,有一个核心的功能,加载商家列表 请求 用户ID 用户的位置(经纬度) 响应 …

使用Python脚本和简单的图形用户界面轻松切割MP3文件

应用场景&#xff1a; 需要将大型MP3文件切割成较小的部分以便上传或发送。需要从MP3文件中提取特定的音频片段&#xff0c;以便用于其他目的。需要快速制作铃声或音乐片段&#xff0c;以用于手机等设备。 源代码&#xff1a; import subprocess import wxclass MyFrame(wx.…

常微分方程ODE和Neural Ordinary Differential Equations

微分方程&#xff08;英語&#xff1a;Differential equation&#xff0c;DE&#xff09;是一種數學方程&#xff0c;用來描述某一類函数與其导数之间的关系。微分方程的解是一個符合方程的函數。而在初等数学的代数方程裡&#xff0c;其解是常数值。 常微分方程&#xff08;英…

蓝桥杯青少组python:第十二届国赛

选择题 1、设s"Hi LanQiao"&#xff0c;运行一下哪个选项代码可以输出"LanQiao"子串&#xff08;&#xff09; A、print(S[-7:]) B、print(s[-6:-1]) C、print(s[-7:0]) D、print(s[-7:0]) 2、已知a2021.0529&#xff0c;运行一下代码选项可以输出2021.0…

c# vs2013 制作水晶报表并导出为 pdf

一两年前接触的&#xff0c;当时没有记录&#xff0c;现在把他写下来。 vs2013制作水晶报表&#xff0c;应该要用到插件安装&#xff0c;可以自行搜索安装插件。 在Views/RPT文件夹下创建.rpt后缀的水晶报表文件&#xff08;这里的文件夹位置根据自身随意更改&#xff09;。 在…

JavaScript数组去重的常见方法 Set filter indexOf

JavaScript实现对象深拷贝的方法&#xff08;5种&#xff09; 知识回调&#xff08;不懂就看这儿&#xff01;&#xff09;场景复现实现数组去重的五种方法1.Set()Array.from()2.filter() indexOf()3.for 嵌套 for&#xff0c;splice 去重4.利用Map()5.利用includes 实际开发问…

如何入门编程

随着信息技术的快速发展&#xff0c;编程已经成为一个越来越重要的技能。那么&#xff0c;我们该如何入门编程呢&#xff1f;欢迎大家积极讨论 一、自学编程需要注意什么&#xff1f; 对于我个人的理解&#xff0c;其实自学编程最重要的就是兴趣。你得培养编程兴趣。 所以在学…

linuxOPS基础_linux文本文件统计及查找

wc命令 显示文件信息 语法 \# wc [选项] 文件名称选项选项说明-l表示lines&#xff0c;行数&#xff08;以回车/换行符为标准&#xff09;-w表示words&#xff0c;单词数 依照空格来判断单词数量-c表示bytes&#xff0c;字节数&#xff08;空格&#xff0c;回车&#xff0c;换…

【LED子系统深度剖析】十、详细实现流程(番外篇)

个人主页:董哥聊技术 我是董哥,高级嵌入式软件开发工程师,从事嵌入式Linux驱动开发和系统开发,曾就职于世界500强公司! 创作理念:专注分享高质量嵌入式文章,让大家读有所得! 文章目录 1、LED驱动初始化流程1.1 LED驱动匹配以及设备的创建1.1.1 gpio_led_probe1.1.2 gpi…

[SpringBoot]Service与Controller层

目录 关于Service 关于Controller 关于各组件的处理流程 补充&#xff1a; Service保证数据完整性是怎么体现的&#xff1f; 以下代表复制属性&#xff0c;把来源adminAddNewParam复制到目标 admin里面 关于Service Service的核心价值在于&#xff1a;组织业务流程&#…

gaussDB的schema创建查询,及其查询下面的表列,修改列类型

修改列类型与众不同 alter table adqm_safe_data_encrypt_job_instance alter COLUMN state TYPE INT4 alter COLUMN state TYPE INT4 pg_catalog.pg_namespace来查看当前数据库中全部的Schema select oid,* from pg_catalog.pg_namespace; 创建schema create schema gs_d…

vscode 配置rust、golang代码格式化方法

一共分三步&#xff1a; 点击左下角齿轮按钮&#xff0c;点击Settings&#xff0c;如下图&#xff1a;点击右上角切换到Settings.json文件。如下图增加rust、golang 配置如下&#xff0c;假如存在默认格式化配置请注释或删除。重启vscode ide&#xff0c;​尝试编写rust、gola…

HTML5+CSS3+JS小实例:简约的垂直选项卡

实例:简约的垂直选项卡 技术栈:HTML+CSS+JS 字体图标库:font-awesome 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="v…

【LED子系统深度剖析】八、小试牛刀

个人主页:董哥聊技术 我是董哥,高级嵌入式软件开发工程师,从事嵌入式Linux驱动开发和系统开发,曾就职于世界500强公司! 创作理念:专注分享高质量嵌入式文章,让大家读有所得! 文章目录 1、硬件管脚确定2、设备树配置3、子系统配置4、编译烧录5、验证5.1 设备树验证5.2 驱…

MySQL — 主从复制介绍

文章目录 主从复制一、概述二、原理三、 搭建主从复制结构3.1 服务器准备3.2 主库配置3.3 从库配置 主从复制 一、概述 ​ 主从复制是指将主数据库的DDL和DML操作通过二进制日志传到从库服务器中&#xff0c;然后在从库上对这些日志重新执行&#xff08;也叫重做&#xff09;…

16-Vue3中常用的 Composition API

目录 1、什么是组合式 API&#xff1f;2、拉开序幕的setup3、ref函数4、reactive函数5、Vue3.0中的响应式原理5.1 vue2.x的响应式5.2 Vue3.0的响应式 6、reactive对比ref7、setup的两个注意点8、计算属性与监视8.1 computed函数8.2 watch函数8.3 watchEffect函数 9、 生命周期1…