程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

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

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
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)
    上次更新: 2025/01/30, 23:55:43
    setup函数中执行顺序
    computed()

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

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