Vue 3 ref 和 reactive 完整指南

引言

Vue 3 引入了新的响应式 API,其中包括 refreactive 两个核心概念。这两个 API 提供了创建和管理响应式数据的新方法。接下来将深入探讨 refreactive 的用法、内部实现以及一些高级用法。

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. refreactive 的内部实现

ref 的内部实现

ref 的内部实现基于一个封装了实际值的对象,这个对象实现了 getset 方法,以便在读取和设置值时能够自动触发依赖更新。

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;
    }
  });
}

tracktrigger

tracktrigger 是响应式系统的核心部分,用于收集依赖和触发更新。

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. 高级用法

使用 toRefstoRef

toRefstoRef 用于将一个响应式对象中的某个属性转换为 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

使用 unrefisRef

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

使用 shallowRefshallowReactive

shallowRefshallowReactive 用于创建浅层的响应式引用。

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);

使用 watchwatchEffect

watchwatchEffect 用于监听响应式数据的变化。

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 组件示例,展示了如何使用 refreactive

创建 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 中 refreactive 的工作原理及其用法。这两个 API 是 Vue 3 中非常强大的工具,它们使得响应式编程变得更加简单和直观。如果你有任何疑问或者需要进一步的帮助,请随时在评论区留言!!!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容