Vue2 data + Vue3 ref/reactive 核心知识点总结

文章目录

Vue2概述

Vue2 中组件的 data 必须是函数,返回一个对象,这是 Vue2 最核心的设计之一

优缺点

好处(优点)

  1. 组件实例数据隔离(最重要)
    组件被多次复用(比如列表里循环多个组件)时,每个组件都会独立调用 data 函数,返回全新对象。
    不会出现一个组件改数据,所有组件一起变的问题。
    本质:对象是引用类型,直接用对象会共享内存,函数返回能保证每次都是新对象。
  2. 响应式系统自动驱动视图
    Vue2 会遍历 data 里的所有属性,用 Object.defineProperty 劫持 getter/setter。
    数据一变,视图自动更新,不用手动操作 DOM。
  3. 集中管理组件状态,代码易维护
    组件自己的数据都放在 data 里,清晰统一,便于阅读、调试、维护。
  4. 搭配 computed、watch 非常丝滑
    data 是响应式源头,计算属性自动依赖收集,监听属性轻松监听变化,开发效率极高。
  5. 简单直观,适合新手
    定义数据 → 模板使用 → 修改数据,流程非常简单,学习成本低。

坏处(缺点 / 局限性)

  1. 新增 / 删除属性无法响应式
    Vue2 只能劫持初始化时已存在的属性:

    // 初始化没有 user.name
    this.user = {}
    this.user.name = '张三' // 不响应式!视图不更新

必须用 Vue.set / this.$set 手动处理,非常麻烦。

  1. 数组下标 / 长度修改不响应
js 复制代码
this.arr[0] = 100 // 不响应
this.arr.length = 0 // 不响应

只能用数组方法(push/pop/splice)或 $set,容易踩坑。

  1. 对象嵌套深时,性能有损耗

Vue2 会递归遍历 data 所有属性做劫持,数据越大、层级越深,初始化开销越大。

  1. 组件数据分散,大型项目难管理

data 是组件级状态,大型项目多人协作时,数据流混乱。

必须搭配 Vuex,增加了学习成本和代码量。

  1. this 指向与模板魔法,容易迷惑新手

模板里直接写 msg,JS 里写 this.msg,本质是代理,但新手不理解原理容易踩坑。

总结

Vue2 让 data 是函数,就是为了避免多个组件实例共享同一个数据对象;用 Object.defineProperty 实现响应式,但带来了新增属性不响应的缺陷。

Vue3 概述

ref():把基本类型(string/number/boolean)包装成响应式对象,底层套一层 .value;

复杂对象也能用 ref,但一般优先用 reactive。

优缺点

优点

  1. 完美支持「基本类型响应式」

    • reactive 管不了 string/number/boolean,只能靠 ref 包装;解决
    • Vue2 基础类型零散定义、没法精细化监听的问题。
  2. 解构不丢响应式(比 reactive 稳)

    • reactive 直接解构会丢失响应:

      js 复制代码
      // reactive坑
      const obj = reactive({a:1})
      let {a} = obj // 丢响应
    • ref 单个变量导出、解构、return 都稳,适合拆分细粒度状态。

  3. 模板自动解包,写起来干净

    模板里不用写 .value:

    js 复制代码
    <p>{{ count }}</p>
    JS 里才加 .value,观感清爽。
  4. 简单轻量,适合零散 / 独立变量

    • 开关、loading、页码、弹窗显隐、倒计时......
  5. 跨组件 / 组合式函数抽离超方便

    写 hooks / 组合函数:

    js 复制代码
    export function useNum(){
      const n = ref(0)
      return {n}
    }

    返回直接用,嵌套少、依赖清晰,比 reactive 好维护。

缺点

  1. JS 里必须写 .value,容易忘、漏写
    新手高频 bug:

    js 复制代码
    count = 100  // ❌直接覆盖,丢响应
    count.value = 100 // ✅正确
  2. 存复杂对象 / 深层数据,不如 reactive 顺手

    js 复制代码
    const user = ref({name:'',age:0})
    // 改深层要写多层value,啰嗦
    user.value.name = '张三'

    深层对象、表单大对象,优先 reactive。

  3. 不能直接整个替换对象(易踩坑)

    js 复制代码
    user.value = {name:'李四'} // 能替换,但依赖追踪要重走

    大规模覆写不如reactive直观,还容易打断监听。

  4. 和原生变量混用容易迷惑
    普通 let/const 没 .value,ref 有;多人协作时,一眼分不清是不是响应式。

  5. 批量状态时代码偏碎
    一堆零散 ref:name、age、sex、phone......代码散,不如 reactive 聚合规整。

reactive 是什么

概述

reactive 靠 Proxy 实现,Proxy 只能包装「对象 / 数组 / Map/Set」引用类型;

Proxy 是 ES6 原生 API,只能拦截引用类型(堆内存对象):
基础语法

js 复制代码
import { reactive } from 'vue'

// 只能放:对象 / 数组 / Map / Set
const 变量名 = reactive(引用类型值)

常用场景写法

  1. 普通对象(表单 / 配置最常用)

    js 复制代码
    <script setup>
    import { reactive } from 'vue'
    
    // 定义
    const form = reactive({
      username: '',
      password: '',
      age: 18
    })
    
    // 修改:直接点属性,不用 .value
    form.username = '张三'
    form.age = 20
    </script>
    
    <template>
      <input v-model="form.username">
    </template>
  2. 数组

    js 复制代码
    const list = reactive([1,2,3])
    list.push(4)       // 响应
    list[0] = 99       // 响应(Vue3 Proxy 原生支持)

深层嵌套对象(天生深度响应)

js 复制代码
const info = reactive({
  user: {
    name: '',
    addr: { city: '' }
  }
})
info.user.addr.city = '上海' // 直接生效,不用$set

Map / Set

js 复制代码
const map = reactive(new Map())
map.set('key', 123) // 响应式更新

搭配组合(企业级标准写法)

js 复制代码
import { reactive, toRefs } from 'vue'

// 1.聚合状态用 reactive
const state = reactive({
  loading: false,
  page: 1,
  list: []
})

// 2.需要解构导出,用 toRefs
const { loading, page, list } = toRefs(state)

一堆相关数据、表单、数组、嵌套对象 → reactive

单个数字 / 布尔 / 字符串 → ref

reactive 要解构 → 必加 toRefs

相关推荐
快乐肚皮38 分钟前
深入理解Loop Engineering
前端·后端
半个落月41 分钟前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
风骏时光牛马1 小时前
VHDL十大经典基础功能设计实例代码合集
前端
小兔崽子去哪了1 小时前
Vue3 + Pinia 集成 IGV.js 实现 BAM 文件在线浏览
javascript·vue.js·后端
hunterandroid1 小时前
Notification 通知:从基础到渠道适配
前端
孟陬1 小时前
Claude Code 巧思 `Ctrl+S` 暂存键
前端·后端
PedroQue991 小时前
V1.6.1性能优化:高频路径提速与代码精简
前端·uni-app
猩猩程序员2 小时前
将 LiteLLM 迁移到 Rust —— 构建最快、最轻量的 AI Gateway
前端
小月土星2 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
lichenyang4532 小时前
JSBridge 分发升级:为什么要从 if-else 变成 Registry > 这是「ASCF 架构升级」系列的第 3 篇
前端