vue.js

关注公众号 jb51net

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

一文搞懂Vue3中的ref和reactive

作者:小林猿~

Vue3中ref用于独立值或整体替换,reactive用于对象/数组的深度响应,访问方式不同,解构需用toRefs保持响应,团队应统一规范,按需选用,本文给大家介绍Vue3中的ref和reactive,感兴趣的朋友一起看看吧

引言

在 Vue3 中,响应式最常用的两个 API 就是 refreactive。很多开发者一开始对它们的区别不够明确,看到任何状态就想用 ref,或者对对象也习惯性用 ref 包一层,导致代码可读性、维护性下降,或者出现解构导致响应丢失、整体替换麻烦等问题。

1. 基本概念

关键区别

2. 访问与解包:模板 vs JS 逻辑

示例:

import { ref, reactive } from 'vue';
export default {
  setup() {
    const loading = ref(false);
    const filters = reactive({ category: '', minPrice: null, maxPrice: null });
    function doSomething() {
      loading.value = true;           // ref
      filters.category = 'electronics'; // reactive
    }
    return { loading, filters, doSomething };
  }
};

3. 场景对比:何时用 ref,何时用 reactive

下面以电商常见需求为例,了解它们的使用差异。

3.1 单值状态 vs 多字段状态

3.2 整体替换 vs 逐字段更新

// 替换时不能直接 cart = newCartObj,否则不会触发响应;需要:
Object.assign(cart, newCartObj);
// 或手动清空 items: cart.items.splice(0), 重置其他字段
`Object.assign` 写法较繁琐,且当对象属性更新逻辑复杂时需注意字段对齐。
- **只修改某些字段/数组操作**:如在购物车中增加、减少某项数量、移除某项、更新优惠券、增加浏览次数等,多是逐字段操作,更适合 `reactive`,写法简洁:
const cart = reactive({ items: [], couponCode: '', total: 0 });
function increase(idx) {
  cart.items[idx].quantity++;
  recalcTotal();
}

如果用 ref,写成 cartRef.value.items[idx].quantity++,多了 .value,可读性略差。

3.3 组合场景示例

以搜索筛选和分页为例,结合 ref/reactive:

<template>
  <input v-model="searchQuery" @keyup.enter="doSearch" placeholder="搜索商品" />
  <select v-model="filters.category">
    <option value="">全部</option>
    <option value="electronics">电子</option>
  </select>
  <div>
    <button @click="prevPage" :disabled="page <= 1">上一页</button>
    <span>第 {{ page }} 页</span>
    <button @click="nextPage">下一页</button>
  </div>
  <div v-if="loading">加载中...</div>
  <ul v-else>
    <li v-for="item in list" :key="item.id">{{ item.name }}</li>
  </ul>
</template>
<script setup>
import { ref, reactive } from 'vue';
const searchQuery = ref('');
const page = ref(1);
const loading = ref(false);
const filters = reactive({ category: '', priceRange: { min: null, max: null } });
const list = ref([]);
async function fetchData() {
  loading.value = true;
  // 构造参数
  const params = {
    q: searchQuery.value,
    category: filters.category,
    min: filters.priceRange.min,
    max: filters.priceRange.max,
    page: page.value
  };
  // 假设调用接口返回 items、hasMore
  const res = await fetchProducts(params);
  list.value = res.items;
  loading.value = false;
}
function doSearch() {
  page.value = 1;
  fetchData();
}
function prevPage() {
  if (page.value > 1) {
    page.value--;
    fetchData();
  }
}
function nextPage() {
  page.value++;
  fetchData();
}
</script>

4. 解构与响应丢失:常见陷阱

5. 深度 vs 浅层响应

示例:若想对顶层字段变化跟踪,但不关心内部深层变化,可用 shallowReactive({ nested: { ... } })

6. 团队实践与语义统一

7. 性能与底层实现简述

8. 常见误区纠正

  1. “所有状态都用 ref”

    • 虽然把对象用 ref(obj) 也能响应,但会导致 JS 逻辑里到处出现 .value,可读性差;解构/传参麻烦;整体替换与逐字段更新语义不够明确。
    • 正确做法应先判断:如果只是想更新字段,推荐 reactive;若经常整体赋新值,ref 包对象可考虑。
  2. “所有状态都用 reactive”

    • 当只需管理单一值时,用 reactive 会将其包在对象里(如 reactive({ count: 0 })),这写法冗余;并且整体替换需要 Object.assign,不够直观。
    • 对于标志位、计数、单值 API 返回数据、Boolean 开关等,推荐用 ref。
  3. 忽视解构导致响应丢失

    • 解构 reactive 对象字段时要用 toRefs;否则解构后的变量再修改无法触发视图更新。面试中若提到解构,需说明解决方案。
  4. 混用场景未做区分

    • 例如把整个表单数据既用 reactive 管理,也在某些地方把它赋值给 ref,再修改一半字段时容易混淆响应;要在代码风格上统一,明确何时整体替换、何时字段更新。

9. 总结

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

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