真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

vue3中的ref、reactive怎么使用

本篇內(nèi)容主要講解“vue3中的ref、reactive怎么使用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“vue3中的ref、reactive怎么使用”吧!

瓊結(jié)網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,瓊結(jié)網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為瓊結(jié)超過千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢,請找那個售后服務(wù)好的瓊結(jié)做網(wǎng)站的公司定做!

reactive()

基本用法

在 Vue3 中我們可以使用 reactive() 創(chuàng)建一個響應(yīng)式對象或數(shù)組:

import { reactive } from 'vue'

const state = reactive({ count: 0 })

這個響應(yīng)式對象其實就是一個 Proxy, Vue 會在這個 Proxy 的屬性被訪問時收集副作用,屬性被修改時觸發(fā)副作用。

要在組件模板中使用響應(yīng)式狀態(tài),需要在 setup() 函數(shù)中定義并返回。



當(dāng)然,也可以使用

響應(yīng)式代理 vs 原始對象

reactive() 返回的是一個原始對象的 Proxy,他們是不相等的:

const raw = {}
const proxy = reactive(raw)

console.log(proxy === raw) // false

原始對象在模板中也是可以使用的,但修改原始對象不會觸發(fā)更新。因此,要使用 Vue 的響應(yīng)式系統(tǒng),就必須使用代理。


const state = { count: 0 }
function add() {
  state.count++
}


為保證訪問代理的一致性,對同一個原始對象調(diào)用 reactive() 會總是返回同樣的代理對象,而對一個已存在的代理對象調(diào)用 reactive() 會返回其本身:

const raw = {}
const proxy1 = reactive(raw)
const proxy2 = reactive(raw)

console.log(proxy1 === proxy2) // true

console.log(reactive(proxy1) === proxy1) // true

這個規(guī)則對嵌套對象也適用。依靠深層響應(yīng)性,響應(yīng)式對象內(nèi)的嵌套對象依然是代理:

const raw = {}
const proxy = reactive({ nested: raw })
const nested = reactive(raw)

console.log(proxy.nested === nested) // true

shallowReactive()

在 Vue 中,狀態(tài)默認(rèn)都是深層響應(yīng)式的。但某些場景下,我們可能想創(chuàng)建一個 淺層響應(yīng)式對象 ,讓它僅在頂層具有響應(yīng)性,這時候可以使用 shallowReactive()

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

// 狀態(tài)自身的屬性是響應(yīng)式的
state.foo++

// 下層嵌套對象不是響應(yīng)式的,不會按期望工作
state.nested.bar++

注意:淺層響應(yīng)式對象應(yīng)該只用于組件中的根級狀態(tài)。避免將其嵌套在深層次的響應(yīng)式對象中,因為其內(nèi)部的屬性具有不一致的響應(yīng)行為,嵌套之后將很難理解和調(diào)試。

reactive() 的局限性

reactive() 雖然強(qiáng)大,但也有以下幾條限制:

  • 僅對對象類型有效(對象、數(shù)組和 Map、Set 這樣的集合類型),而對 string、numberboolean 這樣的原始類型無效。

  • 因為 Vue 的響應(yīng)式系統(tǒng)是通過屬性訪問進(jìn)行追蹤的,如果我們直接“替換”一個響應(yīng)式對象,這會導(dǎo)致對初始引用的響應(yīng)性連接丟失:




  • 將響應(yīng)式對象的屬性賦值或解構(gòu)至本地變量,或是將該屬性傳入一個函數(shù)時,會失去響應(yīng)性:

    const state = reactive({ count: 0 })

    // n 是一個局部變量,和 state.count 失去響應(yīng)性連接
    let n = state.count
    // 不會影響 state
    n++

    // count 也和 state.count 失去了響應(yīng)性連接
    let { count } = state
    // 不會影響 state
    count++

    // 參數(shù) count 同樣和 state.count 失去了響應(yīng)性連接
    function callSomeFunction(count) {
    // 不會影響 state
    count++
    }
    callSomeFunction(state.count)

為了解決以上幾個限制,ref 閃耀登場了!

ref()

Vue 提供了一個 ref() 方法來允許我們創(chuàng)建使用任何值類型的響應(yīng)式 ref 。

基本用法

ref() 將傳入的參數(shù)包裝為一個帶有 value 屬性的 ref 對象:

import { ref } from 'vue'

const count = ref(0)

console.log(count) // { value: 0 }

count.value++
console.log(count.value) // 1

和響應(yīng)式對象的屬性類似,ref 的 value 屬性也是響應(yīng)式的。同時,當(dāng)值為對象類型時,Vue 會自動使用 reactive() 處理這個值。

一個包含對象的 ref 可以響應(yīng)式地替換整個對象:


import { ref } from 'vue'

let state = ref({ count: 0 })
function change() {
  // 這是響應(yīng)式替換
  state.value = ref({ count: 1 })
}


ref 從一般對象上解構(gòu)屬性或?qū)傩詡鬟f給函數(shù)時,不會丟失響應(yīng)性:

參考 前端進(jìn)階面試題詳細(xì)解答

const state = {
  count: ref(0)
}
// 解構(gòu)之后,和 state.count 依然保持響應(yīng)性連接
const { count } = state
// 會影響 state
count.value++

// 該函數(shù)接收一個 ref, 和傳入的值保持響應(yīng)性連接
function callSomeFunction(count) {
  // 會影響 state
  count.value++
}
callSomeFunction(state.count)

ref() 讓我們能創(chuàng)建使用任何值類型的 ref 對象,并能夠在不丟失響應(yīng)性的前提下傳遞這些對象。這個功能非常重要,經(jīng)常用于將邏輯提取到 組合式函數(shù) 中。

// mouse.js
export function useMouse() {
  const x = ref(0)
  const y = ref(0)

  // ...
  return { x, y }
}

import { useMouse } from './mouse.js'
// 可以解構(gòu)而不會失去響應(yīng)性
const { x, y } = useMouse()

ref 的解包

所謂解包就是獲取到 ref 對象上 value 屬性的值。常用的兩種方法就是 .valueunref()。 unref() 是 Vue 提供的方法,如果參數(shù)是 ref ,則返回 value 屬性的值,否則返回參數(shù)本身。

ref 在模板中的解包

當(dāng) ref 在模板中作為頂層屬性被訪問時,它們會被自動解包,不需要使用 .value 。下面是之前的例子,使用 ref() 代替:


import { ref } from 'vue'

const count = ref(0)


還有一種情況,如果文本插值({{ }})計算的最終值是 ref ,也會被自動解包。下面的非頂層屬性會被正確渲染出來。


import { ref } from 'vue'

const object = { foo: ref(1) }



其他情況則不會被自動解包,如:object.foo 不是頂層屬性,文本插值({{ }})計算的最終值也不是 ref:

const object = { foo: ref(1) }

下面的內(nèi)容將不會像預(yù)期的那樣工作:

{{ object.foo + 1 }}

渲染的結(jié)果會是 [object Object]1,因為 object.foo 是一個 ref 對象。我們可以通過將 foo 改成頂層屬性來解決這個問題:

const object = { foo: ref(1) }
const { foo } = object
{{ foo + 1 }}

現(xiàn)在結(jié)果就可以正確地渲染出來了。

ref 在響應(yīng)式對象中的解包

當(dāng)一個 ref 被嵌套在一個響應(yīng)式對象中,作為屬性被訪問或更改時,它會自動解包,因此會表現(xiàn)得和一般的屬性一樣:

const count = ref(0)
const state = reactive({ count })

console.log(state.count) // 0

state.count = 1
console.log(state.count) // 1

只有當(dāng)嵌套在一個深層響應(yīng)式對象內(nèi)時,才會發(fā)生解包。當(dāng) ref 作為 淺層響應(yīng)式對象 的屬性被訪問時則不會解包:

const count = ref(0)
const state = shallowReactive({ count })

console.log(state.count) // { value: 0 } 而不是 0

如果將一個新的 ref 賦值給一個已經(jīng)關(guān)聯(lián) ref 的屬性,那么它會替換掉舊的 ref:

const count = ref(1)
const state = reactive({ count })

const otherCount = ref(2)
state.count = otherCount

console.log(state.count) // 2
// 此時 count 已經(jīng)和 state.count 失去連接
console.log(count.value) // 1

ref 在數(shù)組和集合類型的解包

跟響應(yīng)式對象不同,當(dāng) ref 作為響應(yīng)式數(shù)組或像 Map 這種原生集合類型的元素被訪問時,不會進(jìn)行解包。

const books = reactive([ref('Vue 3 Guide')])
// 這里需要 .value
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// 這里需要 .value
console.log(map.get('count').value)

toRef()

toRef 是基于響應(yīng)式對象上的一個屬性,創(chuàng)建一個對應(yīng)的 ref 的方法。這樣創(chuàng)建的 ref 與其源屬性保持同步:改變源屬性的值將更新 ref 的值,反之亦然。

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

const fooRef = toRef(state, 'foo')

// 更改源屬性會更新該 ref
state.foo++
console.log(fooRef.value) // 2

// 更改該 ref 也會更新源屬性
fooRef.value++
console.log(state.foo) // 3

toRef() 在你想把一個 prop 的 ref 傳遞給一個組合式函數(shù)時會很有用:


import { toRef } from 'vue'

const props = defineProps(/* ... */)

// 將 `props.foo` 轉(zhuǎn)換為 ref,然后傳入一個組合式函數(shù)
useSomeFeature(toRef(props, 'foo'))

當(dāng) toRef 與組件 props 結(jié)合使用時,關(guān)于禁止對 props 做出更改的限制依然有效。如果將新的值傳遞給 ref 等效于嘗試直接更改 props,這是不允許的。在這種場景下,你可以考慮使用帶有 getsetcomputed 替代。

注意:即使源屬性當(dāng)前不存在,toRef() 也會返回一個可用的 ref。這讓它在處理可選 props 的時候非常有用,相比之下 toRefs 就不會為可選 props 創(chuàng)建對應(yīng)的 refs 。下面我們就來了解一下 toRefs

toRefs()

toRefs() 是將一個響應(yīng)式對象上的所有屬性都轉(zhuǎn)為 ref ,然后再將這些 ref 組合為一個普通對象的方法。這個普通對象的每個屬性和源對象的屬性保持同步。

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

// 相當(dāng)于
// const stateAsRefs = {
//   foo: toRef(state, 'foo'),
//   bar: toRef(state, 'bar')
// }
const stateAsRefs = toRefs(state)

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

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

從組合式函數(shù)中返回響應(yīng)式對象時,toRefs 相當(dāng)有用。它可以使我們解構(gòu)返回的對象時,不失去響應(yīng)性:

// feature.js
export function useFeature() {
  const state = reactive({
    foo: 1,
    bar: 2
  })

  // ...
  // 返回時將屬性都轉(zhuǎn)為 ref
  return toRefs(state)
}

import { useFeature } from './feature.js'
// 可以解構(gòu)而不會失去響應(yīng)性
const { foo, bar } = useFeature()

toRefs 只會為源對象上已存在的屬性創(chuàng)建 ref。如果要為還不存在的屬性創(chuàng)建 ref,就要用到上面提到的 toRef。

以上就是 ref、reactive 的詳細(xì)用法,不知道你有沒有新的收獲。接下來,我們來探討一下響應(yīng)式原理。

響應(yīng)式原理

Vue2 的限制

大家都知道 Vue2 中的響應(yīng)式是采? Object.defineProperty() , 通過 getter / setter 進(jìn)行屬性的攔截。這種方式對舊版本瀏覽器的支持更加友好,但它有眾多缺點:

  • 初始化時只會對已存在的對象屬性進(jìn)行響應(yīng)式處理。也是說新增或刪除屬性,Vue 是監(jiān)聽不到的。必須使用特殊的 API 處理。

  • 數(shù)組是通過覆蓋原型對象上的7個?法進(jìn)行實現(xiàn)。如果通過下標(biāo)去修改數(shù)據(jù),Vue 同樣是無法感知的。也要使用特殊的 API 處理。

  • 無法處理像 Map、 Set 這樣的集合類型。

  • 帶有響應(yīng)式狀態(tài)的邏輯不方便復(fù)用。

Vue3 的響應(yīng)式系統(tǒng)

針對上述情況,Vue3 的響應(yīng)式系統(tǒng)橫空出世了!Vue3 使用了 Proxy 來創(chuàng)建響應(yīng)式對象,僅將 getter / setter 用于 ref ,完美的解決了上述幾條限制。下面的代碼可以說明它們是如何工作的:

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)
      return target[key]
    },
    set(target, key, value) {
      target[key] = value
      trigger(target, key)
    }
  })
}

function ref(value) {
  const refObject = {
    get value() {
      track(refObject, 'value')
      return value
    },
    set value(newValue) {
      value = newValue
      trigger(refObject, 'value')
    }
  }
  return refObject
}

不難看出,當(dāng)將一個響應(yīng)性對象的屬性解構(gòu)為一個局部變量時,響應(yīng)性就會“斷開連接”。因為對局部變量的訪問不會觸發(fā) get / set 代理捕獲。

我們回到響應(yīng)式原理。在 track() 內(nèi)部,我們會檢查當(dāng)前是否有正在運行的副作用。如果有,就會查找到存儲了所有追蹤了該屬性的訂閱者的 Set,然后將當(dāng)前這個副作用作為新訂閱者添加到該 Set 中。

// activeEffect 會在一個副作用就要運行之前被設(shè)置
let activeEffect

function track(target, key) {
  if (activeEffect) {
    const effects = getSubscribersForProperty(target, key)
    effects.add(activeEffect)
  }
}

副作用訂閱將被存儲在一個全局的 WeakMap>> 數(shù)據(jù)結(jié)構(gòu)中。如果在第一次追蹤時沒有找到對相應(yīng)屬性訂閱的副作用集合,它將會在這里新建。這就是 getSubscribersForProperty() 函數(shù)所做的事。

trigger() 之中,我們會再次查找到該屬性的所有訂閱副作用。這一次我們?nèi)繄?zhí)行它們:

function trigger(target, key) {
  const effects = getSubscribersForProperty(target, key)
  effects.forEach((effect) => effect())
}

這些副作用就是用來執(zhí)行 diff 算法,從而更新頁面的。

到此,相信大家對“vue3中的ref、reactive怎么使用”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


網(wǎng)頁名稱:vue3中的ref、reactive怎么使用
網(wǎng)站鏈接:http://weahome.cn/article/jsdoii.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部