引言
Vue 3 引入了新的响应式 API,其中包括 ref
和 reactive
两个核心概念。这两个 API 提供了创建和管理响应式数据的新方法。接下来将深入探讨 ref
和 reactive
的用法、内部实现以及一些高级用法。
1. ref
的基本用法
ref
用于创建一个基本类型的响应式引用。
import { ref } from 'vue';
const count = ref(0);
访问 ref
的值
ref
的值可以通过 .value
属性来访问和修改。
console.log(count.value); // 输出: 0
count.value = 1;
console.log(count.value); // 输出: 1
在模板中使用 ref
在 Vue 3 的模板中,可以直接使用 ref
而不需要 .value
。
<template>
<div>
Count: {{ count }}
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
return {
count,
increment
};
}
};
</script>
2. reactive
的基本用法
reactive
用于创建一个对象类型的响应式引用。
import { reactive } from 'vue';
const state = reactive({
count: 0,
message: 'Hello Vue!'
});
访问 reactive
的值
reactive
的值可以直接访问和修改。
console.log(state.count); // 输出: 0
state.count = 1;
console.log(state.count); // 输出: 1
在模板中使用 reactive
在 Vue 3 的模板中,可以直接使用 reactive
的属性。
<template>
<div>
Count: {{ state.count }}
Message: {{ state.message }}
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
count: 0,
message: 'Hello Vue!'
});
function increment() {
state.count++;
}
return {
state,
increment
};
}
};
</script>
3. ref
和 reactive
的内部实现
ref
的内部实现
ref
的内部实现基于一个封装了实际值的对象,这个对象实现了 get
和 set
方法,以便在读取和设置值时能够自动触发依赖更新。
function ref(initialValue) {
let cleanupFn;
const r = {
value: initialValue,
effect: new ReactiveEffect(() => {
cleanupFn && cleanupFn();
cleanupFn = trackRef(r);
})
};
// trackRef 用于收集依赖
function trackRef(ref) {
if (activeEffect) {
track(activeEffect, ref);
return () => {
trigger(activeEffect, ref);
};
}
}
// ReactiveEffect 用于创建响应式效果
class ReactiveEffect {
constructor(fn) {
this.fn = fn;
this.deps = [];
}
run() {
activeEffect = this;
try {
this.fn();
} finally {
activeEffect = undefined;
}
}
}
r.effect.run();
return r;
}
reactive
的内部实现
reactive
的内部实现基于 Proxy 对象。它创建了一个新的代理对象,该对象拦截了原始对象的操作,并在读取或修改属性时触发依赖更新。
function reactive(target) {
return new Proxy(target, {
get(target, key) {
track(target, key);
return target[key];
},
set(target, key, value) {
target[key] = value;
trigger(target, key);
return true;
}
});
}
track
和 trigger
track
和 trigger
是响应式系统的核心部分,用于收集依赖和触发更新。
let activeEffect;
function track(target, key) {
if (activeEffect) {
// 收集依赖
activeEffect.deps.push({ target, key });
}
}
function trigger(target, key) {
if (activeEffect) {
// 触发更新
for (const dep of activeEffect.deps) {
if (dep.target === target && dep.key === key) {
dep.callback();
}
}
}
}
4. 高级用法
使用 toRefs
和 toRef
toRefs
和 toRef
用于将一个响应式对象中的某个属性转换为 ref
。
import { reactive, toRefs, toRef } from 'vue';
const state = reactive({ count: 0 });
const { count } = toRefs(state); // 解构赋值
const countRef = toRef(state, 'count'); // 单独转换
countRef.value++; // 修改 `count` 的值
console.log(state.count); // 输出: 1
使用 unref
和 isRef
unref
用于解包 ref
,如果传入的是 ref
,则返回其 .value
;如果不是 ref
,则直接返回原值。
import { ref, unref, isRef } from 'vue';
const count = ref(0);
const num = 1;
console.log(unref(count)); // 输出: 0
console.log(unref(num)); // 输出: 1
console.log(isRef(count)); // 输出: true
console.log(isRef(num)); // 输出: false
使用 shallowRef
和 shallowReactive
shallowRef
和 shallowReactive
用于创建浅层的响应式引用。
import { shallowRef, shallowReactive } from 'vue';
const count = shallowRef(0);
const state = shallowReactive({ count: 0 });
使用 markRaw
markRaw
用于标记一个对象使其不再成为响应式的。
import { markRaw } from 'vue';
const nonReactiveObj = markRaw({ someProp: 1 });
使用 toRaw
toRaw
用于获取一个响应式对象的原始值。
import { reactive, toRaw } from 'vue';
const state = reactive({ a: 1 });
const rawState = toRaw(state);
使用 watch
和 watchEffect
watch
和 watchEffect
用于监听响应式数据的变化。
import { watch, ref, watchEffect } from 'vue';
const count = ref(0);
// 使用 watch
watch(count, (newVal, oldVal) => {
console.log(`Count changed from ${oldVal} to ${newVal}`);
});
// 使用 watchEffect
watchEffect(() => {
console.log(`Current count is ${count.value}`);
});
5. 示例代码
下面是一个完整的 Vue 3 组件示例,展示了如何使用 ref
和 reactive
。
创建 Vue 应用
确保你已经安装了 Vue CLI:
npm install -g @vue/cli
初始化项目
vue create my-app
cd my-app
编辑 src/App.vue
<template>
<div id="app">
<h1>{{ message }}</h1>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { ref, reactive, toRefs, toRef, unref, isRef } from 'vue';
export default {
setup() {
const state = reactive({ count: 0, message: 'Welcome to Vue 3!' });
const countRef = toRef(state, 'count');
function increment() {
countRef.value++;
}
return {
...toRefs(state), // 解构赋值
countRef,
increment
};
}
};
</script>
运行应用
npm run serve
现在你可以打开浏览器并访问 http://localhost:8080/
来查看你的应用。
结论
通过上述内容,你应该能够更好地理解 Vue 3 中 ref
和 reactive
的工作原理及其用法。这两个 API 是 Vue 3 中非常强大的工具,它们使得响应式编程变得更加简单和直观。如果你有任何疑问或者需要进一步的帮助,请随时在评论区留言!!!
暂无评论内容