你分的清Vue3中哪些是响应式么?
2024-01-14 02:05:32
前言:由一个报错引发的思考
某天,星星君的控制台在星星君的奋笔疾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 中的数据响应式有两种方式:
- 直接声明响应式: 使用
ref()
或reactive()
函数将数据对象包装成响应式对象。 - 隐式响应式: 在组件的
data
选项或setup()
函数中声明的数据对象,也会自动成为响应式对象。
哪些数据类型是响应式的?
Vue3 中,以下数据类型是默认响应式的:
- 基本类型:字符串、数字、布尔值、null、undefined
- 数组(使用
ref()
或reactive()
包装) - 对象(使用
ref()
或reactive()
包装)
哪些数据类型不是响应式的?
以下数据类型不是默认响应式的:
- 普通数组
- 普通对象
- Date 对象
- Map 对象
- Set 对象
markraw 的作用
markraw()
函数可以将一个响应式对象标记为只读,使其不再触发视图更新。这对于一些不需要响应式的数据对象很有用,例如:
- 服务器端返回的数据
- 从其他组件通过
provide/inject
传入的数据 - 状态管理库(如 Vuex)中的数据
Vuex 和响应式
Vuex 是一个状态管理库,它提供了集中式的状态管理解决方案。Vuex 中的状态数据也是响应式的,但与组件中的响应式数据不同,Vuex 中的状态数据是全局的,可以在任何组件中访问。
为了防止 Vuex 状态数据在组件中引起不必要的更新,可以使用 mapState
和 mapGetters
辅助函数,它们可以将 Vuex 状态数据映射到组件的计算属性中。这样,组件只能在计算属性发生改变时更新视图,从而优化了性能。
provide/inject 和响应式
provide/inject
是 Vue3 中用来在组件之间传递数据的机制。通过 provide
选项,可以将数据注入到子组件中。通过 inject
选项,子组件可以访问这些数据。
provide/inject
传递的数据默认也是响应式的。如果需要将数据标记为只读,可以将其包装在 ref()
或 reactive()
函数中,并使用 markraw()
函数将其标记为只读。
性能优化
合理控制响应式行为可以优化应用程序的性能。以下是一些优化建议:
- 只将需要响应式的数据对象设为响应式。
- 避免在复杂类型(如数组、对象)中嵌套响应式数据对象。
- 使用
markraw()
函数标记只读的数据对象。 - 使用 Vuex 来管理全局状态数据。
- 使用
mapState
和mapGetters
优化 Vuex 状态数据的更新。
总结
Vue3 的响应式系统是一个强大的工具,可以简化数据绑定。通过理解哪些数据类型是响应式的,以及如何使用 markraw
、Vuex 和 provide/inject
控制响应式行为,我们可以优化应用程序的性能,创建更流畅、更响应的应用程序。