第二十九节——组合式API定义响应式数据

ref本质也是reactive,ref(obj)等价于reactive({value: obj})

vue3中实现响应式数据的方法是就是使用ref和reactive,所谓响应式就是界面和数据同步,能实现实时更新

vue2中响应式是通过defineProperty实现的,vue3中是通过ES6的Proxy来实现的

一、reactive

1、概念

reactive的参数必须是一个对象,包括json数据和数组都可以,否则不具有响应式

如果给reactive传递了其他对象(如时间对象),默认情况下修改对象界面不会自动更新,如果想更新,可以通过给对象重新赋值来解决。

2、使用

复制代码
<template>
  <div>
    {{ info.name }} -- {{ info.age }}
    <input type="text" onChange="inputChange" />
  </div>
</template>
<script setup>
// reactive属于vue3 新增的组合式api之一 需要从vue中引入
import { reactive } from "vue";

/**
 * 使用 reactive 定义 响应式数据
 * info 改变数据会重新渲染
 *
 * 注意:不能把整个info的值替换
 */
const info = reactive({ name: "张三", age: 18 });

/**
 *
 * 每次输入框变化,修改info对象里面的name属性
 */
const inputChange = (event) => {
  /**
   * 修改后页面会重新渲染
   * 注意:这里的数据流向和之前一致
   * 数据修改是同步,视图渲染是异步
   */
  info.name = event.target.value;
};
</script>

二、ref(实战用的较多)

1、概念

ref的参数可以是基本数据类型,也可以是引用数据类型。ref会把参数加工成一个响应式对象。如果使用的是基本类型响应式依赖Object.defineProperty( ),如果ref使用的是引用类型,底层ref会借助reactive的proxy 定义响应式。

2、基本使用

复制代码
<template>
  <div>
    <!-- 在template里 可以直接使用ref定义的数据 -->
    {{ num }}
    <button @click="add">+1</button>
  </div>
</template>
<script setup>
import { ref } from "vue";

/**
 * 使用 ref 对象把 传入的基本数据类型包装成一个对象
 * 
 * 返回的num的值 是一个对象
 */
const num = ref(1);

const add = () => {
  /**
   * ref 的值 挂在在对象的value属性
   * 
   * 注意:不能整个修改num的值
   */
  num.value += 1
}


</script>

ref和reactive都属于递归监听,也就是数据的每一层都是响应式的,如果数据量比较大,非常消耗性能,非递归监听只会监听数据的第一层

三、shallowRef和shallowReactive

ref和reactive定义的数据每一层都是响应式数据,使用shallowRef和shallowReactive后只有第一层数据具备响应式。语法和ref和reactive一致

1、shallowRef+triggerRef

复制代码
<template>
  <div>
    {{ infos.name }}

    <button @click="updateChildName">修改子集</button>
    {{ num }} 
    <button @click="add">+1</button>
  </div>
</template>
<script setup>
import { shallowRef, triggerRef } from "vue";

const infos = shallowRef({
  name: "张三",
});

const num = shallowRef(1);

const updateChildName = () => {
  // 这一行视图不会改变
  infos.value.name = "李四";
  /**
   * 如果用了shallowRef 还想让界面刷新可以使用
   * 传入要更新的数据
   * 🤔 看场景使用,一般情况下没有太大必要
   */
  triggerRef(infos)
};

const add = () => {
  // 可以正常触发
  num.value += 1
}

</script>

2、shallowReactive

注意:shallowReactive没有类似triggerRef()的方法

复制代码
<template>
  <div>
    {{ infos.name }} -- {{ infos.child.name  }}

    <button @click="updateChildName">修改第一层</button>
    {{ num }}
    <button @click="updateChildName2">修改第二层</button>
  </div>
</template>
<script setup>
import { shallowReactive } from "vue";

const infos = shallowReactive({
  name: "张三",
  child: {
    name: "张三的儿子",
  },
});

const updateChildName = () => {
  // 正常改变
  infos.name = "李四";
};
const updateChildName2 = () => {
  // 无法修改
  infos.child.name = "李四的儿子";
};
</script>

三、toRaw

1、介绍

有些时候我们不希望数据进行响应式实时更新,可以通过toRaw获取ref或reactive引用的原始数据,通过修改原始数据,不会造成界面的更新,只有通过修改ref和reactive包装后的数据时才会发生界面响应式变化。

2、使用

复制代码
<template>
  <div>
    <button @click="update">+1</button>
    {{ info.name }}
    <button @click="rawUpdate">取消响应式修改</button>
  </div>
</template>
<script setup>
import { reactive, toRaw } from "vue";

const info = reactive({
  name: "张三",
});

const update = () => {
  info.name = info.name + 1;
};

const rawUpdate = () => {
  /**
   * 取消响应式
   * 注意:toRaw 只能用作引用数据类型
   */
  const a = toRaw(info);
  
  // 后续修改失去作用
  a.name = '李四'
};
</script>

四、markRaw(了解)

markRaw包装后的数据永远不会被追踪。暂时没发现有啥用,看个热闹即可

五、toRef

toRef 是对定义的响应对象的某个属性进行引用

复制代码
<template>
  <div>
    {{ info.name }} --- {{ info.age }}
    <button @click="updateName">修改名字</button>
  </div>
</template>
<script setup>
import { ref, toRef } from "vue";

const info = {
  name: "张三",
  age: 18,
};
/**
 * 从info对象中取出name属性
 * 并加上响应式
 * 
 * 返回的nameRef 的 value属性的值 就是 name的值
 */
const nameRef = toRef(info, "name");


const updateName = () => {
  // 把name改成李四
  nameRef.value = '李四'
}

</script>

六、toRefs

遍历对象中的所有属性,将其变为响应式数据,这是因为toRef只能传一个key,toRefs所达到的效果与toRef一样

以上最常用的是ref 和 reactive 其它 看个热闹即可

复制代码
const state = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:{
  foo: Ref<number>,
  bar: Ref<number>
}
*/

// 这个 ref 和源属性已经"链接上了"
state.foo++
console.log(stateAsRefs.foo.value) // 2

stateAsRefs.foo.value++
console.log(state.foo) // 3
相关推荐
Csvn3 小时前
性能监控
前端
Highcharts.js3 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn3 小时前
构建工具
前端
FRing034 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷5 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen6 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒6 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫7 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus7 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude
孟陬8 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端