Vue3.0 中 Refs 介紹


ref

接受一個內部值並返回一個響應式且可變的 ref 對象。ref 對象僅有一個 .value property,指向該內部值。

<script setup>
import { ref } from "vue";

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1
</script>

如果將對象分配為 ref 值,則它將被 reactive 函數處理為深層的響應式對象。

類型聲明:

interface Ref<T> {
  value: T
}

function ref<T>(value: T): Ref<T>

有時我們可能需要為 ref 的內部值指定復雜類型。可以在調用 ref 時傳遞一個泛型參數以覆蓋默認推斷,從而簡潔地做到這一點:

const foo = ref<string | number>('foo') // foo 的類型:Ref<string | number>

foo.value = 123 // ok!

如果泛型的類型未知,則建議將 ref 轉換為 Ref<T>

function useState<State extends string>(initial: State) {
  const state = ref(initial) as Ref<State> // state.value -> State extends string
  return state
}

unref

如果參數是一個 ref,則返回內部值,否則返回參數本身。這是 val = isRef(val) ? val.value : val 的語法糖函數。

function useFoo(x: number | Ref<number>) {
  const unwrapped = unref(x) // unwrapped 現在一定是數字類型
}

toRef

<script setup>
import { reactive, toRef } from "vue";

const state = reactive({
  foo: 1,
  bar: 2
})

const fooRef = toRef(state, 'foo')

fooRef.value++
console.log(state.foo) // 2

state.foo++
state.bar--
console.log(fooRef.value) // 3
</script>

當你要將 prop 的 ref 傳遞給復合函數時,toRef 很有用:

export default {
  setup(props) {
    useSomeFeature(toRef(props, 'foo'))
  }
}

即使源 property 不存在,toRef 也會返回一個可用的 ref。這使得它在使用可選 prop 時特別有用,可選 prop 並不會被 toRefs 處理。

toRefs

將響應式對象轉換為普通對象,其中結果對象的每個 property 都是指向原始對象相應 property 的 ref

<script setup>
import { reactive, toRefs } from "vue";

const state = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state)
/*
stateAsRefs 的類型:

{
  foo: Ref<number>,
  bar: Ref<number>
}
*/

// ref 和原始 property 已經“鏈接”起來了
state.foo++
console.log(stateAsRefs.foo.value) // 2

stateAsRefs.foo.value++
console.log(state.foo) // 3
</script>

當從組合式函數返回響應式對象時,toRefs 非常有用,這樣消費組件就可以在不丟失響應性的情況下對返回的對象進行解構/展開:

<script >
import { reactive, toRefs } from "vue";

function useFeatureX() {
  const state = reactive({
    foo: 1,
    bar: 2,
  });

  // 操作 state 的邏輯

  // 返回時轉換為ref
  return toRefs(state);
}

export default {
  setup() {
    // 可以在不失去響應性的情況下解構
    const { foo, bar } = useFeatureX();

    return {
      foo,
      bar,
    };
  },
};
</script>

toRefs 只會為源對象中包含的 property 生成 ref。如果要為特定的 property 創建 ref,則應當使用 toRef

isRef

檢查值是否為一個 ref 對象。

customRef

創建一個自定義的 ref,並對其依賴項跟蹤和更新觸發進行顯式控制。它需要一個工廠函數,該函數接收 track 和 trigger 函數作為參數,並且應該返回一個帶有 get 和 set 的對象。

使用自定義 ref 通過 v-model 實現 debounce 的示例:

<input v-model="text" />
function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

export default {
  setup() {
    return {
      text: useDebouncedRef('hello')
    }
  }
}

類型聲明

function customRef<T>(factory: CustomRefFactory<T>): Ref<T>

type CustomRefFactory<T> = (
  track: () => void,
  trigger: () => void
) => {
  get: () => T
  set: (value: T) => void
}

shallowRef

創建一個跟蹤自身 .value 變化的 ref,但不會使其值也變成響應式的。

const foo = shallowRef({})
// 改變 ref 的值是響應式的
foo.value = {}
// 但是這個值不會被轉換。
isReactive(foo.value) // false

參考創建獨立的響應式值作為 refs

triggerRef

手動執行與 shallowRef 關聯的任何作用 (effect)。

const shallow = shallowRef({
  greet: 'Hello, world'
})

// 第一次運行時記錄一次 "Hello, world"
watchEffect(() => {
  console.log(shallow.value.greet)
})

// 這不會觸發作用 (effect),因為 ref 是淺層的
shallow.value.greet = 'Hello, universe'

// 記錄 "Hello, universe"
triggerRef(shallow)

參考計算和偵聽 - watchEffect

 

免責聲明

本文只是在學習Vue 響應式API的一些筆記,文中的資料也會涉及到引用,具體出處不詳,商業用途請謹慎轉載。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM