编程 写Vue大篇幅的ref、computed,而reactive为何少见?

2024-11-18 21:26:50 +0800 CST views 719

写Vue大篇幅的ref、computed,而reactive为何少见?

在使用Vue3开发项目时,经常会遇到一个vue文件中定义了不下20个ref和computed,这不仅让代码显得冗长,也使得开发者感到困惑。那么有没有更好的解决方案呢?Vue设计ref、computed、reactive的初衷又是什么?让我们从源码和实践中找答案!

理解定义的初衷

Vue官方文档在介绍响应式对象的定义时,顺序为ref、computed、reactive、readonly,这与项目开发中它们的使用频率大致相符。

ref

我们先抛出一个问题:如果给ref b传入的参数a本身也是一个ref类型的值,是通过b.value还是b.value.value来获取值?

const a = ref(1);
const b= ref(a);

// console.log(b.value);
// console.log(a.value);

ref的定义:

function ref<T>(value: T): Ref<UnwrapRef<T>> {
  interface Ref<T> { value: T }
}

传入的value可以是简单值或复杂对象,返回的类型是Ref<UnwrapRef<T>>,确定结果是{ value: x }格式对象。

export type UnwrapRef<T> =
  T extends ShallowRef<infer V>
    ? V
    : T extends Ref<infer V>
      ? UnwrapRefSimple<V>
      : UnwrapRefSimple<T>

通过上述代码分析,ref函数需要对原始值进行处理:如果rawValue是Ref类型,则直接返回rawValue,不做处理。因此,代码中的a === b

const a = ref({ x: 1, y: 2 });
const b= ref(a);

如果rawValue是非Ref类型,则返回RefImpl的实例化对象。

reactive

reactive方法用于返回对象的深层响应式代理,适用于对象类型,默认会解包ref类型。

const count = ref(1);
const obj = reactive({ count });
console.log(obj.count === count.value); // true

需要注意,如果reactive包含集合对象,集合本身不会被解包。

const books = reactive([ref('Vue 3 Guide')]);
console.log(books[0].value);

computed

computed接受一个getter函数,返回一个只读的响应式ref对象。其定义如下:

function computed<T>(
  getter: (oldValue: T | undefined) => T,
  debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>

也可以定义可读可写的computed

function computed<T>(
  options: {
    get: (oldValue: T | undefined) => T;
    set: (value: T) => void;
  },
  debuggerOptions?: DebuggerOptions
): Ref<T>

示例:

const count = ref(1);
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    count.value = val - 1;
  },
});

在这个例子中,plusOne允许我们通过set方法修改count的值,而这个特性在某些场景下非常有用。

watch监听Ref类型值的策略

watch函数可以监听Ref类型的值,不同的监听策略如下:

  • watch(refData, ...)可以触发回调函数,但不会监听深层属性的变化;
  • watch(refData.value, ...)可以监听深层属性的变化,但不能监听refData.value本身的变化。

深入研究源码可以发现,watch函数通过getter来取值,当source是Ref类型时,直接返回source.value

if (isRef(source)) {
  getter = () => source.value;
} else if (isReactive(source)) {
  getter = () => reactiveGetter(source);
}

什么时候使用computed

computed的优势在于,当getter函数中的响应式数据发生变化时,它会自动更新结果。

const name = ref('李磊');
const detail = reactive({ phone: 10000 });
const cptValue = computed(() => {
  return `${name.value}: ${detail.phone}`;
});

watch(cptValue, (newValue) => {
  console.log(newValue);
});

如何简化组件的复杂度

在Vue组件中,当功能复杂度增加时,定义的ref和computed会迅速增加。为了简化,我们可以将逻辑封装到外部模块,例如使用dialog.ts模块集中管理逻辑:

export const useDialog = () => {
  const title = ref('');
  const visible = ref(false);
  // 其他逻辑...
  
  return {
    title,
    visible,
  };
};

这样,在Vue文件中可以直接引用逻辑模块:

const { title, visible } = useDialog();

总结

  • ref适用于简单值的定义,且可以作为响应式引用的基础。
  • computed用于需要依赖其他响应式数据进行动态计算的场景。
  • reactive适用于对象类型的深度响应式需求,但在项目中使用较少。

通过将复杂的逻辑分离到独立的模块中,不仅能减少代码重复,还能提升项目的可维护性。

复制全文 生成海报 Vue 前端开发 响应式编程

推荐文章

Vue3中的Store模式有哪些改进?
2024-11-18 11:47:53 +0800 CST
Vue3中如何处理权限控制?
2024-11-18 05:36:30 +0800 CST
Vue3中如何处理SEO优化?
2024-11-17 08:01:47 +0800 CST
Vue3结合Driver.js实现新手指引功能
2024-11-19 08:46:50 +0800 CST
前端开发中常用的设计模式
2024-11-19 07:38:07 +0800 CST
网站日志分析脚本
2024-11-19 03:48:35 +0800 CST
html一份退出酒场的告知书
2024-11-18 18:14:45 +0800 CST
JS 箭头函数
2024-11-17 19:09:58 +0800 CST
任务管理工具的HTML
2025-01-20 22:36:11 +0800 CST
如何在 Vue 3 中使用 Vuex 4?
2024-11-17 04:57:52 +0800 CST
JS中 `sleep` 方法的实现
2024-11-19 08:10:32 +0800 CST
JavaScript 异步编程入门
2024-11-19 07:07:43 +0800 CST
Python 基于 SSE 实现流式模式
2025-02-16 17:21:01 +0800 CST
Gin 与 Layui 分页 HTML 生成工具
2024-11-19 09:20:21 +0800 CST
thinkphp分页扩展
2024-11-18 10:18:09 +0800 CST
Rust 中的所有权机制
2024-11-18 20:54:50 +0800 CST
Go 并发利器 WaitGroup
2024-11-19 02:51:18 +0800 CST
PHP解决XSS攻击
2024-11-19 02:17:37 +0800 CST
Nginx rewrite 的用法
2024-11-18 22:59:02 +0800 CST
Vue3中如何处理组件间的动画?
2024-11-17 04:54:49 +0800 CST
PHP openssl 生成公私钥匙
2024-11-17 05:00:37 +0800 CST
html流光登陆页面
2024-11-18 15:36:18 +0800 CST
FcDesigner:低代码表单设计平台
2024-11-19 03:50:18 +0800 CST
10个极其有用的前端库
2024-11-19 09:41:20 +0800 CST
JavaScript中设置器和获取器
2024-11-17 19:54:27 +0800 CST
Web浏览器的定时器问题思考
2024-11-18 22:19:55 +0800 CST
Golang实现的交互Shell
2024-11-19 04:05:20 +0800 CST
程序员茄子在线接单