程序员scholar 程序员scholar
首页
  • Web 三剑客

    • HTML
    • CSS
    • JavaScript
  • 现代 JavaScript

    • ES6
    • TypeScript
  • 前端工具库

    • jQuery
    • Ajax
    • Axios
  • Vue 生态

    • Vue2
    • Vue3
    • Vue3 + TS
    • Vuex
  • 小程序开发

    • 微信小程序
    • uni-app
  • 构建工具

    • Webpack
  • 服务端技术

    • Node.js
  • 实时通信

    • WebSocket
    • 第三方登录
  • Element-UI
  • Apache ECharts
后端 (opens new window)
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Web 三剑客

    • HTML
    • CSS
    • JavaScript
  • 现代 JavaScript

    • ES6
    • TypeScript
  • 前端工具库

    • jQuery
    • Ajax
    • Axios
  • Vue 生态

    • Vue2
    • Vue3
    • Vue3 + TS
    • Vuex
  • 小程序开发

    • 微信小程序
    • uni-app
  • 构建工具

    • Webpack
  • 服务端技术

    • Node.js
  • 实时通信

    • WebSocket
    • 第三方登录
  • Element-UI
  • Apache ECharts
后端 (opens new window)
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Vue2

  • Vue3

    • 初识Vue3
    • 组合式API
    • Vue3中的data数据
    • vue3 的 script标签
    • setup函数中执行顺序
    • toRefs() 与 toRef()
      • computed()
      • Vue3弱化this
      • watch() 和 watchEffec()
      • define函数用法
      • defineExpose() 和 ref 属性
      • vue.config.js
      • 生命周期
      • Vue3全局API调用
      • 自定义 Hook
      • 传递数据(props)
      • 路由
      • pinia
      • 组件通信
      • getCurrentInstance() 和 nextTick()
      • Vue3 新组件
    • vue3 + TS 项目集成

    • Vue全家桶
    • Vue3
    scholar
    2024-08-05
    目录

    toRefs() 与 toRef()

    前言

    在 Vue 3 中,响应式数据是组件开发的核心之一,通常我们使用 reactive() 和 ref() 来创建响应式状态。然而,当我们处理复杂对象的属性时,直接解构这些响应式对象可能会导致响应性丢失。因此,Vue 3 提供了 toRefs() 和 toRef() 函数,帮助我们在解构或单独处理某个属性时,保留响应式对象的响应性。


    # 1. 概述

    • toRefs():用于将响应式对象的每个属性转换为 ref,让对象属性保留响应性。
    • toRef():用于将响应式对象的某个单独属性转换为 ref,让这个特定属性保留响应性。

    # 2. 为什么需要 toRefs() 和 toRef()

    在 Vue 3 中,如果我们直接解构一个响应式对象的属性,解构后的变量将不再是响应式的。这意味着,修改解构后的变量不会影响到原始的响应式对象,导致我们在处理这些属性时丢失了响应性。

    错误示例:直接解构响应式对象

    import { reactive } from 'vue';
    
    let person = reactive({
      name: '张三',
      age: 18,
      gender: '男'
    });
    
    // 错误:直接解构属性,解构后的属性不是响应式的
    let { name, age, gender } = person;
    
    // 修改解构后的 name 变量,不会影响原始的 person 对象
    name = '李四';
    console.log(person.name); // 输出仍然是 '张三',没有响应性
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    在这个例子中,name 被解构后不再是响应式的,修改 name 的值不会更新原始的 person 对象中的 name。


    # 3. 使用 toRefs()

    toRefs() 可以将一个响应式对象的每个属性都转换为 ref,从而保留每个属性的响应性。这样即使解构出来的属性,仍然是响应式的,可以正确地反映到原始对象上。

    语法:

    const { prop1, prop2 } = toRefs(reactiveObject);
    
    1

    示例:使用 toRefs() 保持响应性

    import { reactive, toRefs } from 'vue';
    
    let person = reactive({
      name: '张三',
      age: 18,
      gender: '男'
    });
    
    // 使用 toRefs 保留属性的响应性
    let { name, age, gender } = toRefs(person);
    
    console.log(name.value); // 输出 '张三'
    name.value = '李四'; // 修改 ref 属性
    console.log(person.name); // 现在原始 person 对象的 name 也变成了 '李四'
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    执行过程分析:

    1. 原始状态:person 是一个使用 reactive() 创建的响应式对象,包含 name、age 和 gender 属性。
    2. 解构处理:使用 toRefs(),将 person 对象的属性转化为 ref。这样,name、age 和 gender 变成了响应式 ref 对象。
    3. 修改 ref:修改 name.value 后,会自动更新原始 person 对象中的 name。

    # 4. 使用 toRef()

    toRef() 允许我们将响应式对象中的某一个属性转化为 ref。与 toRefs() 不同的是,toRef() 只处理单个属性,而不是整个对象的所有属性。

    语法:

    const refProp = toRef(reactiveObject, 'propertyName');
    
    1

    示例:使用 toRef() 转化单个属性

    import { reactive, toRef } from 'vue';
    
    let person = reactive({
      name: '张三',
      age: 18,
      gender: '男'
    });
    
    // 使用 toRef 将 person 对象的 age 属性转化为 ref
    let ageRef = toRef(person, 'age');
    
    console.log(ageRef.value); // 输出 18
    ageRef.value += 1; // 修改 age 的值
    console.log(person.age); // 输出 19,person 对象的 age 也发生了变化
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    执行过程分析:

    1. 选择属性:我们使用 toRef() 只将 person 对象中的 age 属性转化为 ref,而不对整个对象进行操作。
    2. 修改属性:当我们修改 ageRef.value 时,原始 person 对象的 age 属性会随之更新。

    # 5. toRefs() 与 toRef() 的区别

    • toRefs():将整个对象的所有属性都转换为 ref,适合在解构多个属性时使用,确保所有属性都保持响应性。
    • toRef():只转换某个具体属性为 ref,适合需要单独处理某个属性的情况。

    # 6. 综合使用示例

    下面是一个包含多个属性的响应式对象,我们会演示如何使用 toRefs() 和 toRef() 来处理这些属性。

    示例:结合 toRefs() 和 toRef() 使用

    <template>
      <div>
        <h1>姓名:{{ name }}</h1>
        <h1>年龄:{{ age }}</h1>
        <h1>性别:{{ gender }}</h1>
        <button @click="changeName">修改名字</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="changeGender">修改性别</button>
      </div>
    </template>
    
    <script setup>
    import { reactive, toRefs, toRef } from 'vue';
    
    // 创建响应式对象
    let person = reactive({
      name: '张三',
      age: 18,
      gender: '男'
    });
    
    // 使用 toRefs 将多个属性转化为 ref 对象
    let { name, gender } = toRefs(person);
    
    // 使用 toRef 转化单个属性为 ref 对象
    let age = toRef(person, 'age');
    
    // 修改姓名的函数
    function changeName() {
      name.value = '李四'; // 修改 ref 对象
    }
    
    // 修改年龄的函数
    function changeAge() {
      age.value += 1; // 修改 ref 对象
    }
    
    // 修改性别的函数
    function changeGender() {
      gender.value = gender.value === '男' ? '女' : '男'; // 修改 ref 对象
    }
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42

    解析:

    • name 和 gender:我们使用 toRefs() 将 person 对象中的 name 和 gender 转化为 ref。这样这两个属性在模板中使用时能够保持响应性。
    • age:通过 toRef() 单独提取 age 属性并将其转换为 ref,从而保持响应性。

    # 7. 深入理解响应性丢失的问题

    Vue 3 中的响应式系统是基于 Proxy 对象构建的,它会拦截对属性的访问与修改,保证响应性。然而,当我们直接解构响应式对象时,解构出的变量不再受到 Proxy 的代理控制。因此,任何解构后的属性都失去了响应性。

    示例:直接解构导致的响应性丢失

    import { reactive } from 'vue';
    
    let person = reactive({
      name: '张三',
      age: 18
    });
    
    // 错误的方式:直接解构属性
    let { name, age } = person;
    
    // 修改解构后的 name 变量不会触发视图更新
    name = '李四';
    console.log(person.name); // 仍然是 '张三'
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    在这个例子中,name 被直接解构为一个普通的变量,它已经失去了响应性,无法跟踪和反映原始 person 对象的变化。


    总结

    • toRefs() 和 toRef() 是 Vue 3 中用于解决解构响应式对象时丢失响应性问题的重要工具。
    • toRefs() 适用于批量将响应式对象的所有属性转换为 ref,从而保留响应性。适合当你需要解构多个属性时。
    • toRef() 用于将响应式对象的某个特定属性转换为 ref,适合只需要处理单个属性的情况。
    • 通过 toRefs() 和 toRef(),我们可以确保即使在解构和独立处理对象属性时,也能够保留响应式特性。
    编辑此页 (opens new window)
    setup函数中执行顺序
    computed()

    ← setup函数中执行顺序 computed()→

    Theme by Vdoing | Copyright © 2019-2025 程序员scholar
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式