Vue3中的Ref和Reactive:理解响应式编程

理解:

1.ref是定义简单类型和单一对象

2.reactive是用来定义复杂的类型

响应式编程

在Vue中,响应式编程是一种使数据与UI页面保持同步的方式。当数据变化时,UI会自动更新,反之亦然。这种机制大大简化了前端开发,不必手动处理DOM更新。

Ref()

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

详细信息

res对象是可更改的,就是说你可以为.value赋予新的值。它是响应式的,即所有对.value的操作都将被追踪,并且写操作会触发相对应的作用/副作用。

如果将一个对象赋值给了ref,那么这个对象将通过reactive()转为具有深层次响应式对象。

实例

	import { ref } from 'vue';
	const count = ref(0);
	// 访问数据
	console.log(count.value) // 输出 0

	// 更新数据
	count.value = 1;
	console.log(count.value) // 输出1

为什么要使用Ref

当你在模板中使用了一个ref,然后改变了这个ref的值时,Vue就会自动检测到这个变化,并且相应地更新DOM。这是通过一个基于依赖追踪的响应式系统实现的。当一个组件首次渲染时,Vue会追踪在渲染过程中使用的每一个ref。然后,当一个ref被修改时,它会触发追踪它的组件的一次重新渲染。
另一个ref的好处时,与普通变量不同,你可以将ref传递给函数,同事保留对最新值和响应式连接的访问。当将复杂的逻辑重构为可重用的代码时,这将非常有用。

优势
1.明确的数据访问语法(.value)
2.适用于包装基本数据类型,如数字、字符串等。
3.更容易阅读和理解,适合处理简单的响应式数据。

Reactive()

返回一个对象的响应式代理。可以用于创建响应式对象,而不仅仅时基本数据类型。优势主要在于处理复杂数据结构时更加灵活,能够包装整个对象。

详细信息

响应式转换是“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何ref属性,同时保持响应性。

实例

	import { reactive } from 'vue';
	const user = reactive({
	  name: 'John',
	  age: 30,
	});
	// 访问数据
	console.log(user.name); // 输出 'John'
	// 更新数据
	user.age = 31;
	console.log(user.age) // 输出 31

ref的解包

const count = ref(1)
const obj = reactive({ count })

// ref 会被解包
console.log(obj.count === count.value) // true

// 会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2

// 也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3

reactive()的局限性
1.有限的值类型:它只能用于对象类型(对象、数组和如MapSet这样的集合类型)。它不能持有如Stringnumberboolean这样的原始类型。
2.不能替换整个对象:由于Vue的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:

let state = reactive({ count: 0 })

// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })

3.对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接:

const state = reactive({ count: 0 })

// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++

// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)

优势
1.适用于包装复杂的对象和数据结构,包括嵌套对象。
2.不需要额外的语法(.value),直接访问属性。
3.更适合处理多个相关属性的情况,如表单字段或组件状态。

Ref与Reactive的区别

1.数据类型:ref用于包装基本数据类型(如数字、字符串),而reactive用于包装对象.
2.访问数据:使用ref时,需要通过.value来访问数据,而reactive则允许直接访问属性。
3.数据的包装:ref返回一个包装对象,而reactive返回一个包装后的对象。

Vue3响应式系统的原理

Vue3的响应式系统是基于JavaScript ES6中新增的Proxy对象实现的。官方文档解释响应式系统

创建一个Proxy对象
创建一个Proxy对象,需要传递两个参数:目标对象处理器对象。处理器对象包含了一些方法,用于定义代理对象的行为。

	const target = { name: 'John' };
	const handler = {
	  get(target, key) {
	    console.log(`Getting ${key} property`);
	    return target[key];
	  },
	  set(target, key, value) {
	    console.log(`Setting ${key} property to ${value}`);
	    target[key] = value;
	  }
	};  	
	const proxy = new Proxy(target, handler);
	console.log(proxy.name)  // 会触发 get 拦截器 输出“Getter name property”   "John"
	proxy.age = 30 // 会触发 set 拦截器,输出 “Setter age property to 30”

在上面的代码中,我们创建了一个Proxy对象proxy,它会拦截对target对象的读取和写入操作。