偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Vue.js 響應(yīng)式系統(tǒng):追蹤每一個(gè)變量變化

開(kāi)發(fā) 前端
今天,我們將深入探討 Vue 的響應(yīng)式系統(tǒng)——這個(gè)讓你應(yīng)用充滿活力的隱形引擎。相信我,一旦你理解了它的工作原理,你會(huì)對(duì) Vue 有一個(gè)全新的認(rèn)識(shí)。

你是否體驗(yàn)過(guò)那種神奇的感覺(jué):在 Vue 中更改數(shù)據(jù)時(shí),UI 就自動(dòng)...更新了?不需要手動(dòng)操作 DOM,不需要事件監(jiān)聽(tīng)器,什么都不需要。就是純粹而美妙的響應(yīng)式。但你是否曾想過(guò),這背后到底發(fā)生了什么?Vue 是如何知道你的數(shù)據(jù)何時(shí)發(fā)生變化的?

今天,我們將深入探討 Vue 的響應(yīng)式系統(tǒng)——這個(gè)讓你應(yīng)用充滿活力的隱形引擎。相信我,一旦你理解了它的工作原理,你會(huì)對(duì) Vue 有一個(gè)全新的認(rèn)識(shí)。

Vue 解決的問(wèn)題(你可能甚至沒(méi)有意識(shí)到)

讓我們從一個(gè)簡(jiǎn)單的事實(shí)開(kāi)始:JavaScript 本身并不是響應(yīng)式的。如果你這樣寫(xiě):

let total = 0
let price = 10
let quantity = 2

total = price * quantity
console.log(total) // 20

price = 15
console.log(total) // 仍然是 20... ??

當(dāng) price 變化時(shí),total 并不會(huì)神奇地更新。這是 JavaScript 的正常行為,但這不是我們?cè)诂F(xiàn)代 Web 應(yīng)用中所期望的。我們希望 UI 能自動(dòng)與數(shù)據(jù)保持同步。

Vue 通過(guò)創(chuàng)建我稱(chēng)之為"依賴網(wǎng)絡(luò)"的系統(tǒng)來(lái)解決這個(gè)問(wèn)題——一個(gè)能精確知道應(yīng)用哪些部分依賴于哪些數(shù)據(jù)的系統(tǒng)。當(dāng)數(shù)據(jù)變化時(shí),Vue 可以立即通知所有關(guān)心這個(gè)變化的組件。

引入 Proxy:Vue 的秘密武器

Vue 3 的響應(yīng)式系統(tǒng)建立在 JavaScript Proxy 之上——這是一個(gè)強(qiáng)大的 ES6 特性,允許你攔截和自定義對(duì)對(duì)象的操作(如屬性訪問(wèn)和賦值)。

可以把 Proxy 想象成位于你的代碼和數(shù)據(jù)之間的中間人:

// Vue 創(chuàng)建響應(yīng)式數(shù)據(jù)的簡(jiǎn)化版本
functionreactive(obj) {
returnnewProxy(obj, {
    get(target, key) {
      // "嘿 Vue,有人在讀取這個(gè)屬性!"
      track(target, key)
      return target[key]
    },
    set(target, key, value) {
      // "嘿 Vue,有人在修改這個(gè)屬性!"
      target[key] = value
      trigger(target, key)
      returntrue
    }
  })
}

每次你讀取或?qū)懭腠憫?yīng)式屬性時(shí),Proxy 都會(huì)捕獲這個(gè)操作并告訴 Vue 的依賴追蹤器發(fā)生了什么。這就像有一個(gè)超級(jí)細(xì)心的助手,能注意到你與數(shù)據(jù)的每一次交互。

依賴追蹤的舞蹈

這里變得真正有趣起來(lái)。當(dāng)組件首次渲染時(shí),Vue 會(huì)追蹤渲染過(guò)程中使用的每一個(gè) ref。之后,當(dāng) ref 發(fā)生變化時(shí),它會(huì)觸發(fā)正在追蹤它的組件的重新渲染。

讓我們通過(guò)一個(gè)真實(shí)例子來(lái)分解這個(gè)過(guò)程:

<template>
  <div>
    <h1>{{ user.name }}</h1>
    <p>{{ user.email }}</p>
    <p>Total items: {{ itemCount }}</p>
  </div>
</template>

<script setup>
import { reactive, ref } from 'vue'

const user = reactive({
  name: 'Sarah',
  email: 'sarah@example.com'
})

const itemCount = ref(5)
</script>

當(dāng)這個(gè)組件首次渲染時(shí),幕后發(fā)生了以下事情:

  1. 讀取階段:Vue 注意到渲染函數(shù)讀取了 user.nameuser.email 和 itemCount.value
  2. 追蹤階段:Vue 創(chuàng)建依賴映射:"這個(gè)組件依賴于這三個(gè)數(shù)據(jù)片段"
  3. 監(jiān)聽(tīng)階段:Vue 在這些屬性上設(shè)置隱形的觀察者

現(xiàn)在,當(dāng)你執(zhí)行 user.name = 'John' 這樣的操作時(shí),Proxy 的 setter 會(huì)觸發(fā),Vue 檢查其依賴映射,發(fā)現(xiàn)我們的組件關(guān)心 user.name,于是觸發(fā)重新渲染。只針對(duì)實(shí)際使用 user.name 的組件!

Ref vs Reactive:兩種魔法風(fēng)味

Vue 提供了兩種創(chuàng)建響應(yīng)式數(shù)據(jù)的主要方式,每種都有其獨(dú)特之處:

Refs:包裝器方式

import { ref } from 'vue'

const count = ref(0)
const user = ref({ name: 'Alex' })

// 訪問(wèn)/修改需要使用 .value
console.log(count.value) // 0
count.value++
user.value.name = 'Jordan'

在底層,Vue 在其 getter 中執(zhí)行追蹤,在其 setter 中為 ref 執(zhí)行觸發(fā)。ref 基本上是一個(gè)看起來(lái)像這樣的包裝器對(duì)象:

// 簡(jiǎn)化的 ref 實(shí)現(xiàn)
const myRef = {
_value: 0,
getvalue() {
    track() // 告訴 Vue "有人在讀取這個(gè) ref"
    returnthis._value
  },
setvalue(newValue) {
    this._value = newValue
    trigger() // 告訴 Vue "這個(gè) ref 改變了,更新依賴項(xiàng)!"
  }
}

Reactive:Proxy 方式

import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: { name: 'Alex' }
})

// 直接屬性訪問(wèn)
console.log(state.count) // 0
state.count++
state.user.name = 'Jordan'

Reactive 對(duì)象是 JavaScript Proxy,行為就像普通對(duì)象一樣。不同之處在于,Vue 能夠攔截響應(yīng)式對(duì)象所有屬性的訪問(wèn)和變更,以實(shí)現(xiàn)響應(yīng)式追蹤和觸發(fā)。

深度響應(yīng)式:一路深入

Vue 響應(yīng)式最酷的事情之一是默認(rèn)就是深度的。在 Vue 中,狀態(tài)默認(rèn)是深度響應(yīng)式的。這意味著即使你修改嵌套對(duì)象或數(shù)組,也能檢測(cè)到變化:

const state = reactive({
user: {
    profile: {
      settings: {
        theme: 'dark'
      }
    }
  },
items: ['apple', 'banana']
})

// 所有這些都會(huì)觸發(fā)響應(yīng)式!
state.user.profile.settings.theme = 'light'
state.items.push('orange')
state.items[0] = 'grape'

這是如何工作的?Vue 3 對(duì)響應(yīng)式對(duì)象使用 Proxy,當(dāng)你訪問(wèn)嵌套對(duì)象時(shí),Vue 會(huì)自動(dòng)將其包裝在自己的 Proxy 中。這是一路向下的 Proxy!

性能甜蜜點(diǎn)

你可能會(huì)認(rèn)為所有這些追蹤和監(jiān)聽(tīng)會(huì)很昂貴,但 Vue 在性能方面非常智能。通過(guò)使用 Proxy,Vue.js 可以最小化追蹤依賴的開(kāi)銷(xiāo)。Proxy 本質(zhì)上是惰性的,只在屬性被訪問(wèn)或修改時(shí)應(yīng)用處理程序。

此外,當(dāng)你修改響應(yīng)式狀態(tài)時(shí),DOM 會(huì)自動(dòng)更新。但需要注意的是,DOM 更新不是同步應(yīng)用的。相反,Vue 會(huì)將它們緩沖到更新周期的"下一個(gè) tick",以確保每個(gè)組件只更新一次,無(wú)論你進(jìn)行了多少次狀態(tài)更改。

這意味著你可以這樣做而不用擔(dān)心:

// 所有這些更改都會(huì)被批處理為單個(gè)更新!
state.count++
state.count++
state.count++
state.user.name = 'New Name'
state.items.push('new item')

實(shí)際示例:構(gòu)建購(gòu)物車(chē)

讓我們通過(guò)一些實(shí)際的東西來(lái)看看響應(yīng)式系統(tǒng)的運(yùn)行:

<template>
  <div>
    <h2>Shopping Cart ({{ totalItems }} items)</h2>
    <div v-for="item in cart.items" :key="item.id">
      <span>{{ item.name }} - ${{ item.price }}</span>
      <button @click="removeItem(item.id)">Remove</button>
    </div>
    <p><strong>Total: ${{ totalPrice }}</strong></p>
  </div>
</template>

<script setup>
import { reactive, computed } from'vue'

const cart = reactive({
items: [
    { id: 1, name: 'Coffee', price: 4.99 },
    { id: 2, name: 'Donut', price: 2.49 }
  ]
})

// 這些計(jì)算屬性會(huì)在 cart.items 變化時(shí)自動(dòng)更新
const totalItems = computed(() => cart.items.length)
const totalPrice = computed(() =>
  cart.items.reduce((sum, item) => sum + item.price, 0).toFixed(2)
)

functionremoveItem(id) {
const index = cart.items.findIndex(item => item.id === id)
  cart.items.splice(index, 1) // 這會(huì)觸發(fā)響應(yīng)式!
}
</script>

在這個(gè)例子中:

  • 當(dāng) removeItem() 修改 cart.items 時(shí),Proxy 檢測(cè)到變化
  • Vue 檢查哪些計(jì)算屬性依賴于 cart.items
  • totalItems 和 totalPrice 都會(huì)自動(dòng)重新計(jì)算
  • 模板更新以顯示新值

所有這些都在瞬間發(fā)生,完全不需要手動(dòng)干預(yù)!

調(diào)試超能力

想看看響應(yīng)式系統(tǒng)的運(yùn)行嗎?Vue 提供了 onRenderTracked 和 onRenderTriggered 生命周期鉤子用于調(diào)試:

import { onRenderTracked, onRenderTriggered } from 'vue'

onRenderTracked((event) => {
  console.log('Tracked:', event.target, event.key)
})

onRenderTriggered((event) => {
  console.log('Triggered:', event.target, event.key, event.newValue)
})

這讓你可以確切地看到哪些屬性正在被追蹤,以及是什么導(dǎo)致你的組件重新渲染。對(duì)于調(diào)試性能問(wèn)題非常有用!

常見(jiàn)陷阱(以及如何避免)

響應(yīng)式系統(tǒng)很強(qiáng)大,但有一些需要注意的事項(xiàng):

1. 不要解構(gòu)響應(yīng)式對(duì)象

const state = reactive({ count: 0, name: 'Vue' })

// ? 這會(huì)破壞響應(yīng)式!
let { count } = state
count++ // 這不會(huì)觸發(fā)更新

// ? 改用這種方式
state.count++ // 這樣有效!

當(dāng)我們將響應(yīng)式對(duì)象的原始類(lèi)型屬性解構(gòu)到局部變量中,或者將該屬性傳遞給函數(shù)時(shí),我們將失去響應(yīng)式連接。

2. 不要完全替換響應(yīng)式對(duì)象

let state = reactive({ count: 0 })

// ? 這會(huì)破壞響應(yīng)式連接!
state = reactive({ count: 1 })

// ? 改用這種方式
state.count = 1

3. 記住使用 .value 與 Refs

const count = ref(0)

// ? 在 JavaScript 中,你需要 .value
console.log(count) // 這是 ref 對(duì)象,不是值

// ? 正確的方式
console.log(count.value) // 這是實(shí)際的值

// 注意:在模板中,Vue 會(huì)自動(dòng)解包 refs!
// {{ count }} 在模板中工作正常

這對(duì)你的應(yīng)用為什么重要

理解 Vue 的響應(yīng)式系統(tǒng)不僅僅是學(xué)術(shù)知識(shí)——它能讓你成為更好的 Vue 開(kāi)發(fā)者:

  1. 更好的性能:你會(huì)知道何時(shí)使用 ref 與 reactive,以及如何構(gòu)建數(shù)據(jù)以實(shí)現(xiàn)最佳響應(yīng)式
  2. 更輕松的調(diào)試:你會(huì)理解為什么你的組件會(huì)重新渲染,以及如何修復(fù)響應(yīng)式問(wèn)題
  3. 更清晰的代碼:你會(huì)編寫(xiě)更可預(yù)測(cè)、更可維護(hù)的應(yīng)用程序,充分利用 Vue 的能力

下次當(dāng)你看到 Vue 應(yīng)用在數(shù)據(jù)變化時(shí)神奇地更新 UI 時(shí),你會(huì)確切知道發(fā)生了什么:Proxy、依賴追蹤和高效更新之間的復(fù)雜舞蹈,讓現(xiàn)代 Web 開(kāi)發(fā)感覺(jué)像,嗯,魔法。

你在 Vue 中遇到過(guò)棘手的響應(yīng)式問(wèn)題嗎?你在使用 Vue 響應(yīng)式系統(tǒng)時(shí)最喜歡的"頓悟時(shí)刻"是什么?在下面留言——我很想聽(tīng)聽(tīng)你的經(jīng)驗(yàn)!

原文地址:https://medium.com/@sohail_saifi/the-vue-js-reactivity-system-that-tracks-every-variable-change-2b89cc298393
作者:Sohail Saifi

責(zé)任編輯:武曉燕 來(lái)源: 前端小石匠
相關(guān)推薦

2021-01-22 11:47:27

Vue.js響應(yīng)式代碼

2017-08-30 17:10:43

前端JavascriptVue.js

2022-04-05 16:44:59

系統(tǒng)Vue.js響應(yīng)式

2022-04-09 17:53:56

Vue.js分支切換嵌套的effect

2021-04-14 12:47:50

Vue.jsMJML電子郵件

2018-01-31 15:45:07

前端Vue.js組件

2019-10-15 09:05:07

域插槽組件前端

2022-04-17 09:18:11

響應(yīng)式數(shù)據(jù)Vue.js

2022-02-10 10:48:23

JavaScriptVue.js數(shù)據(jù)

2022-04-16 13:59:34

Vue.jsJavascript

2022-06-23 07:46:34

VueMobx系統(tǒng)

2023-12-11 18:20:21

Vue.js事件機(jī)制傳遞

2019-04-29 14:51:05

前后端JavaVue.js

2020-11-24 10:40:12

Ubuntu 20.0LinuxVue

2025-06-17 08:15:00

VTK.jsThree.js3D

2018-04-04 10:32:13

前端JavascriptVue.js

2016-11-04 19:58:39

vue.js

2017-07-04 17:55:37

Vue.js插件開(kāi)發(fā)

2021-02-10 07:31:12

VuejsElementUI

2024-09-25 12:26:14

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)