第二十九节——组合式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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值