Vue3 中的各種 ref

南珂丶一梦發表於2024-12-01

在 Vue3 中,有許多與響應式相關的函式,例如 toRef、toRefs、isRef、unref 等等。合理地使用這些函式可以在實際開發中大大提高效率。本文將詳細介紹這些函式的用法,讓在實際開發中知道應該使用哪些 API 並能夠熟練地回答面試官的相關問題。

ref()

大家對於 ref 這個 API 肯定都不陌生。在 Vue3 中經常會用到它。它的作用是接收一個值並返回一個響應式的物件。可以透過.value 屬性來訪問和修改這個值。在模板中,可以省略.value,例如在下面的程式碼中,當點選按鈕時,頁面中的 count 會響應式地更改。

<template>
  <div>
    {{ count }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang="ts" setup>
import { ref } from "vue";
const count = ref(1);
const addCount = () => {
  count.value++;
};
</script>

toRef

toRef 可以根據一個響應式物件中的一個屬性,建立一個響應式的 ref。同時這個 ref 和原物件中的屬性保持同步,改變原物件屬性的值這個 ref 會跟著改變,反之改變這個 ref 的值原物件屬性值也會改變,它接收兩個引數,一個是響應式對應,另一個則是屬性值,例如下面程式碼

<template>
  <div>
    {{ count.a }}
    {{ a }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang="ts" setup>
import { ref, toRef } from "vue";
const count = ref({
  a: 1,
  b: 2,
});
const a = toRef(count.value, "a");
const addCount = () => {
  a.value++;
};
</script>

點選按鈕的時候修改了 a 的值,此時 count 中的 a 也會跟著修改,當然這裡的 count 也可以用 reactive

toRefs

toRefs 它可以將一個響應式物件轉成普通物件,而這個普通物件的每個屬性都是響應式的 ref

<template>
  <div>
    {{ count.a }}
    {{ countAsRefs.a }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang="ts" setup>
import { reactive, toRefs } from "vue";
const count = reactive({
  a: 1,
  b: 2,
});
const countAsRefs = toRefs(count);
const addCount = () => {
  countAsRefs.a.value++;
};
</script>

此時程式碼中的countAsRefs型別為

{
  a: Ref<number>,
  b: Ref<number>
}

它的屬性 a 和 b 都是響應式的 ref 物件,同樣的它們和原物件的 count 的屬性也是保持同步的

根據它的特性通常用它來解構一個響應式物件而不會讓其失去響應式

import { reactive, toRefs } from "vue";
const count = reactive({
  a: 1,
  b: 2,
});
const { a, b } = toRefs(count);

此時的 a 和 b 都是一個響應式的 ref 物件,並和原物件的 a 和 b 屬性保持同步

isRef()

isRef 顧名思義它是用來判斷某個值是否是 ref,注意:它判斷不了這個值是不是 reactive(可以使用 isReactive 判斷)

import { reactive, isRef, ref } from "vue";
const count = ref(1);
const testObj = reactive({
  a: 1,
});
console.log(isRef(count)); //true
console.log(isRef(testObj)); //false

unref()

其實它是一個語法糖

val = isRef(val) ? val.value : val;

如果是 ref 則返回它的內部值,否則則返回它本身。透過這個語法糖可以看出它可以對響應式物件解除響應式引用,比如只想獲取一個響應式的值,但不想要它的響應式可以使用它解除引用。 例如

<template>
  <div>
    {{ unRefAsCount }}
    {{ count }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang="ts" setup>
import { unref, ref } from "vue";
const count = ref(1);
let unRefAsCount = unref(count);
const addCount = () => {
  count.value++;
};
</script>

程式碼中的 unRefAsCount 是不具備響應式的

shallowRef

透過翻譯可以看出它是淺層的 ref,什麼是淺層的 ref 呢? 與 ref 不同的是隻有.value 是響應式的,再深層的屬性則不具備響應式

<template>
  <div>
    {{ shallowObj.a }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang="ts" setup>
import { shallowRef } from "vue";

const shallowObj = shallowRef({
  a: 1,
});
const addCount = () => {
  //不會觸發頁面更新
  shallowObj.value.a++;
};
</script>

但是如果將 addCount 改為修改整個.value 就會觸發響應式了

const addCount = () => {
  let temp = shallowObj.value.a;
  temp++;
  shallowObj.value = {
    a: temp,
  };
};

triggerRef

它可以讓淺層的 ref 即 shallowRef 深層屬性發生改變的時候強制觸發更改,比如上面觸發不了響應式的程式碼示例加入triggerRef

<template>
  <div>
    {{ shallowObj.a }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang="ts" setup>
import { shallowRef, triggerRef } from "vue";

const shallowObj = shallowRef({
  a: 1,
});

const addCount = () => {
  shallowObj.value.a++;
  //加入triggerRef強制觸發更改
  triggerRef(shallowObj);
};
</script>

此時再看頁面效果則觸發了響應式

customRef

顧名思義它是自定義的 ref,可以透過 customRef 來顯式的追蹤某個值的響應式變化,它接收一個函式,這個函式接受 track 和 trigger 兩個函式作為引數,並返回一個帶有 get 和 set 方法的物件。比如下面封裝一個自定義的響應式物件 myRef,同時控制它只有值小於 4 才會觸發響應式

<template>
  <div>
    {{ count }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang="ts" setup>
import { customRef } from "vue";
const myRef = (value: number) => {
  const customValue = customRef((track, trigger) => {
    return {
      get() {
        //通知vue需要追蹤後續內容的變化,這裡可以自由控制
        track();
        return value;
      },
      set(newValue) {
        console.log(newValue); //myRef.value=xxx的xxx值
        //加trigger則觸發響應式,通知vue更新頁面,這裡可以自由控制是否加trigger
        if (value < 4) trigger();
        value = newValue;
      },
    };
  });
  return customValue;
};

const count = myRef(0);
const addCount = () => {
  count.value++;
};
</script>

可以看到當 count 大於 4 的時候便失去了響應式

總結

本篇文章詳細介紹了 Vue3 中各種 ref 的用法,其中包括

  • ref(): 接收一個值並返回一個響應式的物件,可以使用.value 屬性來訪問和修改這個值。
  • toRef(obj, key): 根據一個響應式物件中的一個屬性,建立一個響應式的 ref,並且該 ref 和原物件中的屬性保持同步。 -toRefs(obj): 將一個響應式物件轉換成一個普通物件,其中普通物件的每個屬性都是響應式的 ref。
  • isRef(value): 判斷某個值是否是 ref 物件。
  • unref(value): 用於解除響應式引用
  • shallowRef(value): 建立一個淺層的 ref,只有 value 屬性是響應式的,深層的屬性不具備響應式。
  • triggerRef(ref): 強制淺層的 ref 發生改變時觸發響應式。
  • customRef(factory): 自定義 ref 物件,可以顯式地追蹤某個值的響應式變化。

相關文章