用人人都听得懂的话来阐述 ref、reactive、isRef、toRefs
ref() 函数用来根据给定的值创建一个响应式的数据对象,ref() 函数调用的返回值是一个对象,这个对象上只包含一个 value 属性
{{count}}
import { ref } from 'vue'export default { setup () { const count = ref(0) console.log(count.value) // 0 count.value++ console.log(count.value) // 1 }}
注意:只在setup函数内部访问ref函数需要加.value
reactive() 函数用来根据给定的值创建一个响应式的数据对象,reactive()和ref() 函数调用的返回值是一个对象,只是不会包含value这个属性
{{obj.count}}
import { reactive } from 'vue'export default { setup () { const obj = reactive({ count:1 }) console.log(obj.count) // 0 obj.count++ console.log(obj.count) // 1 }}
注意:而只使用 reactive 的问题是,使用组合函数时必须始终保持对这个所返回对象的引用以保持响应性
// 组合函数:function useMousePosition() { const pos = reactive({ x: 0, y: 0, }) // ... return pos}// 消费者组件export default { setup() { // 这里会丢失响应性! const { x, y } = useMousePosition() return { x, y, } // 这里会丢失响应性! return { ...useMousePosition(), } // 这是保持响应性的唯一办法! // 你必须返回 `pos` 本身,并按 `pos.x` 和 `pos.y` 的方式在模板中引用 x 和 y。 return { pos: useMousePosition(), } },}
toRefs API 用来提供解决此约束的办法——它将响应式对象的每个 property 都转成了相应的 ref
在reactive()使用组合函数会失去响应性!通过toRefs()返回即可保持响应性
function useMousePosition() { const pos = reactive({ x: 0, y: 0, }) // ... return toRefs(pos)}// x & y 现在是 ref 形式了!const { x, y } = useMousePosition()
isRef,用于检查一个对象是否是ref对象
const unwrapped = isRef(foo) ? foo.value : foo;
总结
// 风格 1: 将变量分离 如同 ref()let x = 0let y = 0function updatePosition(e) { x = e.pageX y = e.pageY}// --- 与下面的相比较 --- 如同 reactive()// 风格 2: 单个对象const pos = { x: 0, y: 0,}function updatePosition(e) { pos.x = e.pageX pos.y = e.pageY}
一共有两种变量风格:
- 就像你在普通 JavaScript 中区别声明基础类型变量与对象变量时一样区别使用 ref 和 reactive。我们推荐你在此风格下结合 IDE 使用类型系统。
- 所有的地方都用 reactive,然后记得在组合函数返回响应式对象时使用 toRefs。这降低了一些关于 ref 的心智负担,但并不意味着你不需要熟悉这个概念。
在这个阶段,我们认为现在就强制决定 ref vs. reactive 的最佳实践还为时过早。我们建议你对以上两种方式都进行尝试,选择与你的心智模型更加配合的风格。我们将持续收集周边生态中的用户反馈,并最终在这个问题上提供更明确、更统一的实践指导建议。