首页 > 编程笔记 > JavaScript笔记
阅读:10
Vue3 toRefs()和toRef()函数的用法(附带实例)
在介绍 toRefs() 与 toRef() 函数之前,先来演示使用 reactive() 函数进行代码简化的问题,下面是简化前的代码:
在模板中,每次获取 reactive() 函数中的数据都要写上“state.”,如果需要获取多次,则操作会重复多次。现在想简化一下代码,去掉“state.”,也就是像下面这样编写代码:
同样在 setup() 函数中返回的代码也需要做相应的修改,将 reactive 对象中的 msg、person 和 courses 取出后分别放入返回的对象中。
或者利用扩展运算符简化代码:
如何让从 reactive 对象中读取出的属性也是响应式的呢?答案是:可以利用本节介绍的 toRefs() 和 toRef() 函数。toRefs() 函数能一次性将 reactive 对象包含的所有属性值都包装成 ref 对象,而 toRef 函数只能一次处理一个属性。
详细来说,toRefs() 函数接收一个 reactive 对象,内部会包装每个属性值生成 ref 对象,最后返回包含所有属性值的 ref 对象的对象。而 toRef() 函数接收 reactive 对象和属性名,内部会创建此属性名对应属性值的 ref 对象,并返回这个 ref 对象。
一般我们会使用 toRefs() 函数来解决上面的问题,代码如下:
当然可以进一步简化代码,直接用扩展运算符解构 toRefs() 函数生成的对象。
那么如果使用 toRef() 函数来处理,要如何编写代码呢?可以先多次调用 toRef() 函数生成各个属性的 ref 对象,再添加到返回对象中,代码如下:
当然可以进一步优化成如下代码:
<div id="app"> <ul> <li>msg: {{state.msg}}</li> <li>person: {{state.person}}</li> <li>courses: {{state.courses}}</li> </ul> <button @click="updateState">更新 state</button> </div> <script> const { createApp, reactive } = Vue; createApp({ setup(props, context) { const state = reactive({ msg: 'Hello World!', person: { name: 'Tom', age: 22 }, courses: ['JavaScript', 'BOM', 'DOM'], }); const updateState = () => { state.msg += '--'; state.person = { name: 'Jack', age: 33 }; state.courses = ['JavaScript2', 'BOM2', 'DOM2']; }; return { state, updateState, }; }, }).mount('#app'); </script>
在模板中,每次获取 reactive() 函数中的数据都要写上“state.”,如果需要获取多次,则操作会重复多次。现在想简化一下代码,去掉“state.”,也就是像下面这样编写代码:
<ul> <li>msg: {{msg}}</li> <li>person: {{person}}</li> <li>courses: {{courses}}</li> </ul>
同样在 setup() 函数中返回的代码也需要做相应的修改,将 reactive 对象中的 msg、person 和 courses 取出后分别放入返回的对象中。
return { msg: state.msg, person: state.person, courses: state.courses, updateMsg, };
或者利用扩展运算符简化代码:
return { ...state, updateMsg };但是,运行代码并点击按钮更新 msg 后,发现页面上的 msg 显示不会更新。这是因为后面的两种方式传入的 msg、person 和 course 属性值都是非响应式数据,而要想页面能自动更新,必须要求 setup() 函数返回对象中的属性是 ref 对象或 reactive 对象。
如何让从 reactive 对象中读取出的属性也是响应式的呢?答案是:可以利用本节介绍的 toRefs() 和 toRef() 函数。toRefs() 函数能一次性将 reactive 对象包含的所有属性值都包装成 ref 对象,而 toRef 函数只能一次处理一个属性。
详细来说,toRefs() 函数接收一个 reactive 对象,内部会包装每个属性值生成 ref 对象,最后返回包含所有属性值的 ref 对象的对象。而 toRef() 函数接收 reactive 对象和属性名,内部会创建此属性名对应属性值的 ref 对象,并返回这个 ref 对象。
一般我们会使用 toRefs() 函数来解决上面的问题,代码如下:
// 生成包含多个 ref 对象的对象 const stateRefs = toRefs(state); return { msg: stateRefs.msg, person: stateRefs.person, courses: stateRefs.courses, updateState, };
当然可以进一步简化代码,直接用扩展运算符解构 toRefs() 函数生成的对象。
return { ...toRefs(state), updateState, };
那么如果使用 toRef() 函数来处理,要如何编写代码呢?可以先多次调用 toRef() 函数生成各个属性的 ref 对象,再添加到返回对象中,代码如下:
// 生成各个属性的 ref 对象 const msgRef = toRef(state, 'msg'); const personRef = toRef(state, 'person'); const coursesRef = toRef(state, 'courses'); return { msg: msgRef, person: personRef, courses: coursesRef, updateState, };
当然可以进一步优化成如下代码:
return { msg: toRef(state, 'msg'), person: toRef(state, 'person'), courses: toRef(state, 'courses'), updateState };虽然使用 toRefs() 和 toRef() 函数都能解决解构 reactive 对象的属性读取响应式丢失的问题,但从代码可读性上来看,明显使用 toRefs() 函数的代码更简洁。toRef() 函数更适用于只对单个属性进行处理的场景,而 toRefs() 函数更适用于对所有属性进行处理的场景。