最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文搞懂Vue3中的ref和reactive

 更新時間:2025年06月27日 16:07:50   作者:小林猿~  
Vue3中ref用于獨立值或整體替換,reactive用于對象/數(shù)組的深度響應,訪問方式不同,解構(gòu)需用toRefs保持響應,團隊應統(tǒng)一規(guī)范,按需選用,本文給大家介紹Vue3中的ref和reactive,感興趣的朋友一起看看吧

引言

在 Vue3 中,響應式最常用的兩個 API 就是 refreactive。很多開發(fā)者一開始對它們的區(qū)別不夠明確,看到任何狀態(tài)就想用 ref,或者對對象也習慣性用 ref 包一層,導致代碼可讀性、維護性下降,或者出現(xiàn)解構(gòu)導致響應丟失、整體替換麻煩等問題。

1. 基本概念

  • ref:用于包裝一個獨立的響應式值。創(chuàng)建后會返回一個包含 .value 的對象,內(nèi)部對 .value 做響應式跟蹤。模板中 Vue 會自動解包 .value,在 JS 邏輯里需顯式用 .value 訪問或修改。

    import { ref } from 'vue';
    const count = ref(0);
    count.value++; // 觸發(fā)響應
  • reactive:用于把一個對象或數(shù)組變?yōu)轫憫?Proxy。返回的就是該對象的代理,訪問寫法如 state.prop,對內(nèi)部嵌套對象/數(shù)組會遞歸轉(zhuǎn)為響應式。

    import { reactive } from 'vue';
    const state = reactive({ a: 1, b: { c: 2 } });
    state.a = 3;          // 觸發(fā)響應
    state.b.c = 5;        // 嵌套也響應

關鍵區(qū)別

  • ref 更適合包裝原始類型或需要整體替換的場景;.value 代表實際值。
  • reactive 適合包裝多字段對象/數(shù)組,直接訪問屬性更簡潔。

2. 訪問與解包:模板 vs JS 邏輯

  • 模板中:Vue 會自動對 ref 進行解包。例如:

    <template>
      <div>{{ count }}</div>         <!-- 如果 count = ref(0),模板會顯示 0 -->
      <div>{{ state.a }}</div>       <!-- state = reactive({ a: ... }) -->
    </template>

    模板里使用 ref、reactive 返回的變量都可直接寫,不用加 .value。

  • JS 邏輯里

    • ref:必須用 .value 訪問/賦值。
    • reactive:直接用 state.prop、state.prop = newValue

示例:

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 單值狀態(tài) vs 多字段狀態(tài)

  • 單值、標志位、計數(shù)器、頁碼、布爾 loading、是否收藏 等,典型用 ref。語義上就是一個變量,訪問/修改都集中在 .value,且若需要整體替換該值(如重置、切換)也很方便。

    const page = ref(1);
    const loading = ref(false);
    const isFavorite = ref(false);
    // 切換時: page.value = 1; isFavorite.value = true/false
  • 多個相關字段聚合成一個對象,如搜索篩選條件、表單數(shù)據(jù)、購物車項集合和詳情對象等,用 reactive 更直觀:

    const filters = reactive({
      keyword: '',
      category: '',
      price: { min: null, max: null }
    });
    // 修改時: filters.keyword = 'xxx'; filters.price.min = 10

    若拆成多個 ref:const keyword = ref(''), const category = ref(''), …,當字段較多時不易管理;也無法一次性傳遞或傳入 API。

3.2 整體替換 vs 逐字段更新

  • 需要整體替換狀態(tài)對象:如“加載遠程購物車數(shù)據(jù)并直接賦予當前狀態(tài)”“一鍵清空并恢復初始對象”等。用 ref 包對象更簡單:

    const cartRef = ref({ items: [], couponCode: '', total: 0 });
    // 加載后整體替換
    cartRef.value = newCartObj;

    若用 reactive

    const cart = reactive({ items: [], couponCode: '', total: 0 });
// 替換時不能直接 cart = newCartObj,否則不會觸發(fā)響應;需要:
Object.assign(cart, newCartObj);
// 或手動清空 items: cart.items.splice(0), 重置其他字段
`Object.assign` 寫法較繁瑣,且當對象屬性更新邏輯復雜時需注意字段對齊。
- **只修改某些字段/數(shù)組操作**:如在購物車中增加、減少某項數(shù)量、移除某項、更新優(yōu)惠券、增加瀏覽次數(shù)等,多是逐字段操作,更適合 `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 組合場景示例

以搜索篩選和分頁為例,結(jié)合 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;
  // 構(gòu)造參數(shù)
  const params = {
    q: searchQuery.value,
    category: filters.category,
    min: filters.priceRange.min,
    max: filters.priceRange.max,
    page: page.value
  };
  // 假設調(diào)用接口返回 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>
  • searchQuery, page, loading, list 獨立值用 ref;filters 多字段用 reactive。兩者結(jié)合,寫法語義清晰、邏輯分明。

4. 解構(gòu)與響應丟失:常見陷阱

  • reactive 解構(gòu)后喪失響應

    const state = reactive({ a: 1, b: 2 });
    const { a, b } = state;
    // 這里的 a、b 都是普通值,不再是響應式。模板或 watch 無法再跟蹤它們。
    • 解決:若想解構(gòu)并保持響應,可用 toRefs

      import { reactive, toRefs } from 'vue';
      const state = reactive({ a: 1, b: 2 });
      const { a, b } = toRefs(state);
      // a、b 都是 ref,保持響應
  • ref 解構(gòu)注意
    對于 const count = ref(0),一般直接用 count;不應做 const { value } = count,因為拿到的 value 是初始值,后續(xù)對 count.value 修改不會更新這個解構(gòu)后的 value 變量,也不會觸發(fā)響應。

  • 整體替換 vs 解構(gòu)
    如果本來想整體替換 reactive 對象,解構(gòu)后再合并新對象會更復雜。一般用 ref 包對象來明確表示整體替換。

5. 深度 vs 淺層響應

  • reactive 默認深度遞歸:內(nèi)部嵌套對象/數(shù)組會在訪問時或初始化時轉(zhuǎn)為 Proxy。
  • ref 包對象:當值是對象或數(shù)組時,Vue 內(nèi)部會對其做 reactive 處理,達到深度響應。但訪問時仍需 .value。
  • shallowReactive / shallowRef:在特殊場景下,如果不想對深層嵌套做自動響應,可使用淺響應 API。但多數(shù)情況下默認深度足夠。

示例:若想對頂層字段變化跟蹤,但不關心內(nèi)部深層變化,可用 shallowReactive({ nested: { ... } })

6. 團隊實踐與語義統(tǒng)一

  • 保持一致性:團隊可制定簡單約定,比如:

    • 單值用 ref;多字段狀態(tài)用 reactive。
    • 若有大量整體替換場景,將對應對象用 ref 包裹,并在注釋或文檔中標明“此狀態(tài)將整體賦值替換”。
    • 避免隨意把對象都用 ref 包一層或把所有狀態(tài)都放到一個大 reactive 對象,導致解構(gòu)、替換、類型推斷等復雜。
  • TypeScript 友好:無論 ref 還是 reactive,都有相應類型推斷??山Y(jié)合接口定義:

    interface Cart { items: CartItem[]; couponCode: string; total: number; }
    const cartRef = ref<Cart>({ items: [], couponCode: '', total: 0 });
    // 或 reactive:
    const cart = reactive<Cart>({ items: [], couponCode: '', total: 0 });
    • 如果用 reactive,類型推斷里訪問 cart.items 等一目了然;用 ref 包對象時訪問需 .value.items,類型也清晰,但習慣上需注意。
  • 可讀性與維護:若某狀態(tài)對象很大且只在特定場景整體替換,ref 包對象能讓代碼一眼看出“這是一個整體”;若多個位置需單字段修改,用 reactive 寫法更簡潔。結(jié)合團隊項目實際需求,選擇更貼近業(yè)務意圖的方式。

7. 性能與底層實現(xiàn)簡述

  • 底層都是 Proxy & effectreactive 底層用 Proxy 攔截 get/set;ref 底層實現(xiàn)封裝了對 .value 的 track/trigger,如果值是對象內(nèi)部也會遞歸轉(zhuǎn) reactive。
  • 性能差異極小:兩者在常規(guī)使用下性能相當。區(qū)別主要在語義和寫法。
  • 初始化開銷:reactive 在訪問深層屬性時會懶遞歸(或初始化時深度遍歷,取決內(nèi)部實現(xiàn)策略),而 ref 包基本類型開銷更?。坏趯ο髨鼍?,開銷差異在可接受范圍。通常不必為性能過度擔心,而是根據(jù)使用場景選擇更清晰易維護的方式。

8. 常見誤區(qū)糾正

  1. “所有狀態(tài)都用 ref”

    • 雖然把對象用 ref(obj) 也能響應,但會導致 JS 邏輯里到處出現(xiàn) .value,可讀性差;解構(gòu)/傳參麻煩;整體替換與逐字段更新語義不夠明確。
    • 正確做法應先判斷:如果只是想更新字段,推薦 reactive;若經(jīng)常整體賦新值,ref 包對象可考慮。
  2. “所有狀態(tài)都用 reactive”

    • 當只需管理單一值時,用 reactive 會將其包在對象里(如 reactive({ count: 0 })),這寫法冗余;并且整體替換需要 Object.assign,不夠直觀。
    • 對于標志位、計數(shù)、單值 API 返回數(shù)據(jù)、Boolean 開關等,推薦用 ref。
  3. 忽視解構(gòu)導致響應丟失

    • 解構(gòu) reactive 對象字段時要用 toRefs;否則解構(gòu)后的變量再修改無法觸發(fā)視圖更新。面試中若提到解構(gòu),需說明解決方案。
  4. 混用場景未做區(qū)分

    • 例如把整個表單數(shù)據(jù)既用 reactive 管理,也在某些地方把它賦值給 ref,再修改一半字段時容易混淆響應;要在代碼風格上統(tǒng)一,明確何時整體替換、何時字段更新。

9. 總結(jié)

  • 核心認識refreactive 并非完全可互換,而是分別針對“獨立值/整體替換”和“復合對象/逐字段更新”場景設計。理解兩者語義、訪問方式和解構(gòu)注意。

  • 建議

    • 先分析業(yè)務需求:狀態(tài)是單一值還是多字段聚合?是否需要整體替換或只是字段更新?是否會在多個地方解構(gòu)或傳遞?
    • 按需選擇:簡單標志、計數(shù)、頁碼、loading、Boolean、ID 等用 ref;多個字段組合成配置、表單、購物車列表、復雜詳情對象等用 reactive。
    • 若有整體替換需求,也可用 ref 包對象。若用 reactive,注意用 Object.assign 或手動清理以觸發(fā)響應。
    • 謹慎解構(gòu):了解 toRefs 用法;在 Composition API 里盡量直接操作 ref/reactive,避免無謂解構(gòu)。
    • 團隊約定:統(tǒng)一風格,避免不同開發(fā)者隨意選擇導致代碼風格混亂。
  • 一句話概括

    “Vue3 里 ref 是給單一值或需要整體替換的狀態(tài)包裝響應式,reactive 是給對象/數(shù)組做深度響應,用在多字段狀態(tài)更新更直觀,兩者語義不同、寫法不同,應根據(jù)需求選用。”

到此這篇關于玩懂Vue3的ref和reactive的文章就介紹到這了,更多相關vue ref和reactive內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • vue3項目中代碼出現(xiàn)紅色波浪線的問題及解決

    vue3項目中代碼出現(xiàn)紅色波浪線的問題及解決

    這篇文章主要介紹了vue3項目中代碼出現(xiàn)紅色波浪線的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue.js系列中的vue-fontawesome使用

    vue.js系列中的vue-fontawesome使用

    這篇文章主要介紹了vue.js系列中的vue-fontawesome使用,需要的朋友可以參考下
    2018-02-02
  • VueJs 將接口用webpack代理到本地的方法

    VueJs 將接口用webpack代理到本地的方法

    本篇文章主要介紹了VueJs 將接口用webpack代理到本地的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • 基于vue3開發(fā)mobile-table適用于移動端表格

    基于vue3開發(fā)mobile-table適用于移動端表格

    這篇文章主要給大家介紹了關于如何基于vue3開發(fā)mobile-table適用于移動端表格的相關資料,需要的朋友可以參考下
    2024-03-03
  • vue單頁應用加百度統(tǒng)計代碼(親測有效)

    vue單頁應用加百度統(tǒng)計代碼(親測有效)

    這篇文章主要介紹了vue單頁應用加百度統(tǒng)計代碼的解決方法,需要的朋友參考下吧
    2018-01-01
  • vue項目打包清除console.log的四種方法總結(jié)

    vue項目打包清除console.log的四種方法總結(jié)

    大家在項目開發(fā)的時候,需要看看一些后端接口返回的結(jié)果,會多次使用console.log項目開發(fā)完成打包的時候,發(fā)現(xiàn)控制臺一堆的console.log,非常頭疼,下面這篇文章主要給大家介紹了關于vue項目打包清除console.log的四種方法,需要的朋友可以參考下
    2023-04-04
  • 詳解vue高級特性

    詳解vue高級特性

    這篇文章主要介紹了vue高級特性的相關知識,文中介紹非常細致,幫助大家更好的參考和學習,感興趣的朋友可以了解下
    2020-06-06
  • vue+render+jsx實現(xiàn)可編輯動態(tài)多級表頭table的實例代碼

    vue+render+jsx實現(xiàn)可編輯動態(tài)多級表頭table的實例代碼

    這篇文章主要介紹了vue+render+jsx實現(xiàn)可編輯動態(tài)多級表頭table的實例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的工作或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • vue基礎之詳解ElementUI的表單

    vue基礎之詳解ElementUI的表單

    這篇文章主要為大家詳細介紹了vue基礎之ElementUI的表單,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 詳解Vue3的響應式原理解析

    詳解Vue3的響應式原理解析

    這篇文章主要為大家介紹了Vue3的響應式原理解析,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12

最新評論

曲松县| 峡江县| 喀喇沁旗| 张家港市| 龙岩市| 墨脱县| 集贤县| 和平区| 磐石市| 北京市| 墨脱县| 隆林| 高碑店市| 晋州市| 思南县| 高台县| 当阳市| 顺平县| 湘乡市| 辛集市| 通城县| 塔城市| 南康市| 重庆市| 阳山县| 遂平县| 梓潼县| 潞西市| 华阴市| 游戏| 西乌| 丰都县| 山丹县| 乃东县| 攀枝花市| 洪洞县| 芜湖县| 来安县| 深泽县| 廊坊市| 湟中县|