????????在组合式 API 中,推荐使用?ref()?函数来声明响应式状态。ref()
?接收参数,并将其包裹在一个带有?.value
?属性的 ref 对象中返回。
注意,在模板中使用 ref 时,我们不需要附加?.value
。为了方便起见,当在模板中使用时,ref 会自动解包 (有一些注意事项)。
????????为什么我们需要使用带有?.value
?的 ref,而不是普通的变量?为了解释这一点,我们需要简单地讨论一下 Vue 的响应式系统是如何工作的。
????????当你在模板中使用了一个 ref,然后改变了这个 ref 的值时,Vue 会自动检测到这个变化,并且相应地更新 DOM。这是通过一个基于依赖追踪的响应式系统实现的。当一个组件首次渲染时,Vue 会追踪在渲染过程中使用的每一个 ref。然后,当一个 ref 被修改时,它会触发追踪它的组件的一次重新渲染。
????????在标准的 JavaScript 中,检测普通变量的访问或修改是行不通的。然而,我们可以通过 getter 和 setter 方法来拦截对象属性的 get 和 set 操作。该?.value
?属性给予了 Vue 一个机会来检测 ref 何时被访问或修改。在其内部,Vue 在它的 getter 中执行追踪,在它的 setter 中执行触发。
reactive()
????
还有另一种声明响应式状态的方式,即使用?reactive()
?API。与将内部值包装在特殊对象中的 ref 不同,reactive()
?将使对象本身具有响应性。
????????响应式对象是?JavaScript 代理,其行为就和普通对象一样。不同的是,Vue 能够拦截对响应式对象所有属性的访问和修改,以便进行依赖追踪和触发更新。reactive()
?将深层地转换对象:当访问嵌套对象时,它们也会被?reactive()
?包装。当 ref 的值是一个对象时,ref()
?也会在内部调用它。与浅层 ref 类似,这里也有一个?shallowReactive()?API 可以选择退出深层响应性。
reactive()
?的局限性? ? ? ? 1、它只能用于对象类型
? ? ? ? 2、由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失。
let state = reactive({ count: 0 })
// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })
????????3、当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接
? ? ? ? ref和reactive都能设置响应性,reactive由于只能给对象设置响应性,并存在重新赋值以及解构赋值会丢失响应式的问题,官方更推荐使用ref()。ref()给对象设置响应式本质上也是过了一遍reactive()。