vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue3中ref和reactive区别

vue3中ref和reactive的区别举例详解

作者:Hopebearer_

ref和reactive是Vue3中构建响应式数据的两大核心 API,虽然它们在使用上相似,但底层机制和适用场景有明显不同,这篇文章主要介绍了vue3中ref和reactive区别的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、核心机制对比

特性refreactive
包装对象RefImpl类实现Proxy代理对象
响应式原理通过 .value 的 getter/setter 拦截深度代理对象的属性访问
数据类型支持任意类型(推荐基本类型)仅对象/数组/集合类型
深层响应式自动展开(对象会转为 reactive)默认深层响应
模板自动解包支持(顶层属性自动解包)不支持(需保持对象引用)
TS类型推断Ref 类型包裹原始类型推断

二、底层实现剖析

1. reactive简单实现

const reactive = (target) => {
  return new Proxy(target, {
    get(target, key) {
      // 依赖收集
      track(target, key)
      return Reflect.get(target, key)
    },
    set(target, key, value, receiver) {
      const oldValue = target[key]
      const result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        // 触发更新
        trigger(target, key)
      }
      return result
    }
    // 其他拦截操作...
  })
}
targetMap = WeakMap({
  target: Map({
    key: Set(effect1, effect2, ...)
  })
});

2. ref 实现原理

class RefImpl {
  constructor(value) {
    this._value = isObject(value) ? reactive(value) : value;
    this.dep = new Set(); // 依赖集合
  }

  get value() {
    track(this.dep); // 依赖收集
    return this._value;
  }

  set value(newVal) {
    if (this._value !== newVal) {
      this._value = isObject(newVal) ? reactive(newVal) : newVal;
      trigger(this.dep); // 触发更新
    }
  }
}

const ref = (value) => new RefImpl(value);

三、实战场景对比

1. 基本类型处理

// 正确用法
const count = ref(0) // ✅ 自动类型推断为 Ref<number>

// 错误尝试
const count = reactive(0) // ❌ 参数必须是对象类型

2. 对象类型处理

// ref 处理对象(自动解包)
const user = ref({
  name: 'John',
  address: {
    city: 'New York'
  }
})

// 等效于 reactive 写法
const user = reactive({
  name: 'John',
  address: reactive({
    city: 'New York'
  })
})

// 访问方式对比
console.log(user.value.name) // ref 需要 .value
console.log(user.name)        // reactive 直接访问

3. 数组处理

// ref 数组
const listRef = ref([1, 2, 3])
listRef.value.push(4) // ✅ 正确修改方式

// reactive 数组
const listReactive = reactive([1, 2, 3])
listReactive.push(4) // ✅ 直接操作

四、高级特性差异

1. 响应式丢失问题

// reactive 的解构问题
const state = reactive({ count: 0 })
const { count } = state // ❌ 失去响应性

// ref 的 解构
const countRef = ref(0)
const count = countRef // ❌ 仍需通过 .value 访问

// 正确解构方式(reactive)
const state = reactive({ count: 0 })
const countRef = toRef(state, 'count') // ✅ 保持响应

2. 类型替换场景

// ref 允许整体替换
const data = ref({ items: [] })
data.value = fetchData() // ✅ 响应式更新

// reactive 需保持引用
const data = reactive({ items: [] })
Object.assign(data, fetchData()) // ✅ 正确方式
data = fetchData() ❌ 破坏响应性

五、性能对比分析

操作ref(基本类型)reactive(对象)差异原因
创建速度★★★★☆★★★☆☆Proxy初始化成本较高
属性访问★★★★☆★★★☆☆Proxy拦截带来额外开销
深层监听★☆☆☆☆★★★★★Proxy自动深度代理
内存占用较低较高Proxy对象占用更多内存

六、最佳实践

1. 组合式函数规范

// 推荐返回 ref 保持灵活性
function useCounter(initial = 0) {
  const count = ref(initial)
  return { count }
}

// 复杂状态使用 reactive + toRefs
function useUser() {
  const state = reactive({
    name: '',
    age: ''
  })
  return { ...toRefs(state) }
}

2. 表单处理策略

// 复杂表单使用 reactive
const form = reactive({
  username: '',
  password: '',
  preferences: {
    theme: 'light',
    notifications: true
  }
})

// 单个表单字段使用 ref
const searchQuery = ref('')

七、特殊场景处理

1. DOM 引用

获取元素对象或者组件对象只能使用 ref ,reactive无法处理 DOM 引用

<script setup>

const inputRef = ref(null)
</script>

<templete>
  <div ref="inputRef"></div>
</templete>

2. 第三方库集成

// 需要保持引用的场景
const chartInstance = ref(null)

// 响应式配置对象
const options = reacitve({
  title: { text: '热销' },
  series: [ ... ]
})

八、总结选择策略

1. 优先使用 ref 的场景

2. 优先使用 reactive 的场景

3. 混合使用

3.1 reactive 嵌套 ref

const state = reactive({
  count: ref(0), // 基础类型 ref ,自动解包
  user: ref<User>({ name: '' }) // 对象类型 ref ,自动解包
})
state.count++ // 直接操作数字(等价于 state.count.value++)
state.user.name = 'john' // 直接操作对象(等价于 state.user.value.name)

3.2 ref 嵌套 reactive

const complexRef = ref({
  data: reactive({ /*...*/ }), // 嵌套 reactive 对象
  status: 'loading'  // 普通属性(非响应式)
})
complexRef.value.data.key = "value";  // 直接修改 reactive 对象
complexRef.value.status = "success";  // 修改普通属性(非响应式)
complexRef.value = {  // 替换整个对象(触发响应式更新)
  data: reactive({ /*...*/ }),
  status: 'success'
};

总结 

到此这篇关于vue3中ref和reactive的区别详解的文章就介绍到这了,更多相关vue3中ref和reactive区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文