首页 > 编程笔记 > JavaScript笔记 阅读:10

Vue3 toRefs()和toRef()函数的用法(附带实例)

在介绍 toRefs() 与 toRef() 函数之前,先来演示使用 reactive() 函数进行代码简化的问题,下面是简化前的代码:
<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() 函数更适用于对所有属性进行处理的场景。

相关文章