返回

你分的清Vue3中哪些是响应式么?

前端

前言:由一个报错引发的思考

某天,星星君的控制台在星星君的奋笔疾Code之下出现了一个看起来很简单的报错:

[Vue warn]: Avoid using non-observable types such as Array, Object and Date as reactive properties since they will not trigger re-renders. Use observable collections or mark them as readonly with Vue.markRaw() instead.

这个问题看起来很简单,大概意思是一些复杂类型设置为响应式会有性能的损耗,需要用 markraw 来标记它们为只读。

响应式系统简介

为了理解这个报错,我们先来回顾一下 Vue3 的响应式系统。Vue3 使用 Proxy 实现响应式系统,它可以追踪数据对象的改变,并自动触发视图的更新。

Vue3 中的数据响应式有两种方式:

  1. 直接声明响应式: 使用 ref()reactive() 函数将数据对象包装成响应式对象。
  2. 隐式响应式: 在组件的 data 选项或 setup() 函数中声明的数据对象,也会自动成为响应式对象。

哪些数据类型是响应式的?

Vue3 中,以下数据类型是默认响应式的:

  • 基本类型:字符串、数字、布尔值、null、undefined
  • 数组(使用 ref()reactive() 包装)
  • 对象(使用 ref()reactive() 包装)

哪些数据类型不是响应式的?

以下数据类型不是默认响应式的:

  • 普通数组
  • 普通对象
  • Date 对象
  • Map 对象
  • Set 对象

markraw 的作用

markraw() 函数可以将一个响应式对象标记为只读,使其不再触发视图更新。这对于一些不需要响应式的数据对象很有用,例如:

  • 服务器端返回的数据
  • 从其他组件通过 provide/inject 传入的数据
  • 状态管理库(如 Vuex)中的数据

Vuex 和响应式

Vuex 是一个状态管理库,它提供了集中式的状态管理解决方案。Vuex 中的状态数据也是响应式的,但与组件中的响应式数据不同,Vuex 中的状态数据是全局的,可以在任何组件中访问。

为了防止 Vuex 状态数据在组件中引起不必要的更新,可以使用 mapStatemapGetters 辅助函数,它们可以将 Vuex 状态数据映射到组件的计算属性中。这样,组件只能在计算属性发生改变时更新视图,从而优化了性能。

provide/inject 和响应式

provide/inject 是 Vue3 中用来在组件之间传递数据的机制。通过 provide 选项,可以将数据注入到子组件中。通过 inject 选项,子组件可以访问这些数据。

provide/inject 传递的数据默认也是响应式的。如果需要将数据标记为只读,可以将其包装在 ref()reactive() 函数中,并使用 markraw() 函数将其标记为只读。

性能优化

合理控制响应式行为可以优化应用程序的性能。以下是一些优化建议:

  • 只将需要响应式的数据对象设为响应式。
  • 避免在复杂类型(如数组、对象)中嵌套响应式数据对象。
  • 使用 markraw() 函数标记只读的数据对象。
  • 使用 Vuex 来管理全局状态数据。
  • 使用 mapStatemapGetters 优化 Vuex 状态数据的更新。

总结

Vue3 的响应式系统是一个强大的工具,可以简化数据绑定。通过理解哪些数据类型是响应式的,以及如何使用 markraw、Vuex 和 provide/inject 控制响应式行为,我们可以优化应用程序的性能,创建更流畅、更响应的应用程序。