原文合集地址如下,有需要的朋友可以關(guān)注
本文地址
合集地址
引言
React 和 Vue 都是當(dāng)今最流行的前端框架,它們都實(shí)現(xiàn)了組件化開(kāi)發(fā)模式。為了優(yōu)化性能,兩者都采用了虛擬DOM技術(shù)。當(dāng)組件狀態(tài)發(fā)生改變時(shí),它們會(huì)使用虛擬DOM進(jìn)行局部渲染比對(duì),只更新必要的DOM節(jié)點(diǎn),從而避免重新渲染整個(gè)組件樹(shù)。本文將從React和Vue的組件更新原理入手,剖析兩者虛擬DOM difer算法的異同點(diǎn)。React通過(guò)comparing virtual DOM components and re-rendering only difference,而Vue通過(guò)響應(yīng)式依賴(lài)追蹤確定組件invalidated狀態(tài)。盡管兩者技術(shù)實(shí)現(xiàn)不同,但目的都是實(shí)現(xiàn)增量更新提高性能。本文還將通過(guò)代碼實(shí)例,說(shuō)明兩者的Domin difer流程、對(duì)比粒度、更新觸發(fā)等關(guān)鍵區(qū)別。讀者將對(duì)React和Vue增量更新的內(nèi)在原理有更深的理解,學(xué)會(huì)在實(shí)踐中根據(jù)應(yīng)用場(chǎng)景選擇更合適的框架。
React、Vue如何實(shí)現(xiàn)組件更新
React和Vue是兩個(gè)流行的JavaScript庫(kù),用于構(gòu)建用戶界面。它們都有自己的組件,下面將簡(jiǎn)單介紹一下更新原理。
React的組件更新機(jī)制:
在React中,組件更新是由虛擬DOM(Virtual DOM)和diff算法驅(qū)動(dòng)的。當(dāng)組件的狀態(tài)(state)或?qū)傩裕╬rops)發(fā)生變化時(shí),React會(huì)進(jìn)行虛擬DOM的重新渲染,并將新的虛擬DOM與舊的虛擬DOM進(jìn)行比較,找出需要更新的部分,然后只更新這些部分到實(shí)際的DOM。
React的組件更新流程如下:
- 組件狀態(tài)或?qū)傩园l(fā)生變化。
- React調(diào)用組件的
render()
方法重新渲染虛擬DOM。 - React將新的虛擬DOM與舊的虛擬DOM進(jìn)行比較,找出需要更新的部分。
- React通過(guò)最小化DOM操作,只更新需要變化的部分到實(shí)際的DOM。
- 組件更新完成,觸發(fā)相應(yīng)的生命周期方法(如
componentDidUpdate
)。
下面是一個(gè)簡(jiǎn)單的React組件的例子,展示了組件的更新機(jī)制:
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
handleClick = () => {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}
在上面的例子中,當(dāng)用戶點(diǎn)擊"Increment"按鈕時(shí),handleClick
方法會(huì)更新組件的狀態(tài)count
。React會(huì)重新調(diào)用render()
方法重新渲染虛擬DOM,并將新的虛擬DOM與舊的虛擬DOM進(jìn)行比較,然后只更新變化的部分(這里是<p>Count: {this.state.count}</p>
)到實(shí)際的DOM。
Vue的組件更新機(jī)制:
在Vue中,組件更新是由響應(yīng)式系統(tǒng)驅(qū)動(dòng)的。Vue使用了一種名為"依賴(lài)追蹤"的機(jī)制,它會(huì)在組件渲染過(guò)程中追蹤組件所依賴(lài)的數(shù)據(jù),并建立起依賴(lài)關(guān)系。當(dāng)依賴(lài)的數(shù)據(jù)發(fā)生變化時(shí),Vue會(huì)通知相關(guān)的組件進(jìn)行更新。
Vue的更新過(guò)程大致如下:
- 數(shù)據(jù)變化時(shí),setter 觸發(fā)依賴(lài),標(biāo)記組件為臟數(shù)據(jù)
- 在下一輪事件循環(huán)中,Vue 會(huì)調(diào)用 patch 函數(shù),比對(duì)新舊虛擬 DOM 樹(shù)
- 通過(guò) diff 算法比較樹(shù)的差異,得到需要更新的最小節(jié)點(diǎn)
- 只對(duì)變化的部分進(jìn)行 DOM 操作,更新視圖
diff 算法的主要步驟是:
- 對(duì)比新舊節(jié)點(diǎn),是否為同一節(jié)點(diǎn)
- 如果不是,直接替換該節(jié)點(diǎn)及子節(jié)點(diǎn)
- 如果是,對(duì)比新舊節(jié)點(diǎn)的屬性是否變化
- 對(duì)比子節(jié)點(diǎn),使用鍵值優(yōu)化順序復(fù)雜度
- 遞歸對(duì)比所有子節(jié)點(diǎn)
通過(guò)這種方式,Vue 可以只更新變化的部分,避免不必要的 DOM 操作。
下面是一個(gè)簡(jiǎn)單的Vue組件的例子,展示了組件的更新機(jī)制:
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
}
</script>
在上面的例子中,當(dāng)用戶點(diǎn)擊"Increment"按鈕時(shí),increment
方法會(huì)更新組件的數(shù)據(jù)count
。Vue會(huì)檢測(cè)到count
的變化,并通知組件重新渲染。然后Vue使用虛擬DOM進(jìn)行比較,只更新變化的部分(這里是<p>Count: {{ count }}</p>
)到實(shí)際的DOM。
總結(jié):
React和Vue都采用了類(lèi)似的組件更新機(jī)制,它們都通過(guò)比較虛擬DOM或追蹤依賴(lài)來(lái)實(shí)現(xiàn)高效的組件更新。React和Vue都使用虛擬DOM和diff算法,這些機(jī)制使得組件的更新變得高效,只更新必要的部分,提高了應(yīng)用的性能。
React與Vue更新的區(qū)別
Vue
- 使用數(shù)據(jù)響應(yīng)系統(tǒng),通過(guò)改變組件的數(shù)據(jù)屬性來(lái)觸發(fā)更新。
- 當(dāng)組件的 data、props、computed 等屬性改變時(shí),會(huì)觸發(fā) setter,標(biāo)記組件為“臟”。
- 在下一輪事件循環(huán)中,會(huì)批量觸發(fā)這些“臟”組件的重新渲染。
React
- 使用狀態(tài)(state)和屬性(props)來(lái)控制組件。
- 當(dāng)狀態(tài)或?qū)傩愿淖儠r(shí),會(huì)觸發(fā)重新渲染。
- React 使用 Virtual DOM 來(lái)提高性能,只會(huì)針對(duì)改變的組件進(jìn)行最小化渲染。
相同點(diǎn) - 兩者都是聲明式框架,通過(guò)狀態(tài)/數(shù)據(jù)變化控制界面。
- 都使用虛擬 DOM ,進(jìn)行增量更新提高性能。
區(qū)別 - Vue 側(cè)重響應(yīng)式數(shù)據(jù),React 更側(cè)重狀態(tài)管理。
- Vue 使用模板,React 使用 JSX。
- Vue 批量異步更新,React 同步更新。
- Vue 依賴(lài)數(shù)據(jù)變化觸發(fā)更新,React 通過(guò) setState/useState 控制。
總體來(lái)說(shuō),兩者都使用了類(lèi)似的虛擬DOM和增量更新機(jī)制,但在觸發(fā)更新的方式上有差異。Vue 更加主動(dòng),而 React 更加顯式地控制。
什么是Diff算法
diff 算法是虛擬 DOM 中用于增量更新的關(guān)鍵算法。它的主要作用是對(duì)比兩棵虛擬 DOM 樹(shù)的差異,運(yùn)算出需要更新的最小量 DOM 操作。
diff 算法的基本步驟如下:
- 用虛擬 DOM 構(gòu)建出新的DOM樹(shù)(樹(shù)A)
- 將新的DOM樹(shù)與舊的DOM樹(shù)(樹(shù)B)進(jìn)行對(duì)比找出差異
- 對(duì)比過(guò)程中,首先比較樹(shù)A和樹(shù)B的根節(jié)點(diǎn)
- 如果根節(jié)點(diǎn)不相同,直接替換整個(gè)DOM樹(shù)
- 如果根節(jié)點(diǎn)相同,再遞歸地對(duì)比和更新它的屬性、子節(jié)點(diǎn)等
- 只更新變化的部分,不修改相同的節(jié)點(diǎn)
- 最后將變化渲染到真實(shí)DOM中
diff算法的時(shí)間復(fù)雜度為O(n),它通過(guò)以下優(yōu)化進(jìn)一步提升了性能:
- Web UI中DOM節(jié)點(diǎn)跨層級(jí)的移動(dòng)操作特別少,可以忽略不計(jì)
- 擁有相同類(lèi)的兩個(gè)組件生成相似的樹(shù)形結(jié)構(gòu),擁有較高的移位率
- 通過(guò)唯一id區(qū)分節(jié)點(diǎn),可以根據(jù)id直接判斷兩個(gè)節(jié)點(diǎn)是否相同
這里是一個(gè)簡(jiǎn)化的React Diff算法的實(shí)現(xiàn)示例。它包含了比較根節(jié)點(diǎn)、屬性和子節(jié)點(diǎn)的邏輯。當(dāng)根節(jié)點(diǎn)類(lèi)型不同時(shí),創(chuàng)建新節(jié)點(diǎn)并替換舊節(jié)點(diǎn)。當(dāng)屬性不同時(shí),更新屬性。對(duì)于子節(jié)點(diǎn),通過(guò)遍歷舊子節(jié)點(diǎn)和新子節(jié)點(diǎn)來(lái)進(jìn)行比較,并進(jìn)行遞歸的Diff算法調(diào)用。根據(jù)比較結(jié)果,進(jìn)行增加、刪除或更新相應(yīng)的節(jié)點(diǎn)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-580822.html
// 舊的虛擬DOM樹(shù)
let oldVDOM = {
tag: 'div',
attrs: {
id: 'container'
},
children: [
{tag: 'p', attrs: {class: 'paragraph'}},
{tag: 'span', attrs: {class: 'span'}}
]
}
// 新的虛擬DOM樹(shù)
let newVDOM = {
tag: 'div',
attrs: {
id: 'container'
},
children: [
{tag: 'p', attrs: {class: 'paragraph'}},
{tag: 'span', attrs: {class: 'span-new'}} // span類(lèi)名變化
]
}
// diff算法
function diff(oldTree, newTree) {
// 1. 比較根節(jié)點(diǎn)
if(oldTree.tag !== newTree.tag) {
// 根節(jié)點(diǎn)不同,返回新樹(shù)
return newTree
}
// 2. 比較屬性
if(oldTree.attrs.id !== newTree.attrs.id) {
// id變化,更新屬性
newTree.attrs = newTree.attrs
}
// 3. 比較子節(jié)點(diǎn)
constchildChanges = []
// 使用key進(jìn)行優(yōu)化
oldTree.children.forEach(child => {
const newChild = newTree.children.find(c => c.key === child.key)
// 深度遞歸對(duì)比子節(jié)點(diǎn)
const changedChild = diff(child, newChild)
childChanges.push(changedChild)
})
newTree.children = childChanges
return newTree
}
// 最終只會(huì)更新 span 的類(lèi)名變化
const newVDOM = diff(oldVDOM, newVDOM)
兩者的diff算法的區(qū)別
Vue 和 React 雖然都采用了虛擬 DOM 和 diff 算法,但在具體的 diff 實(shí)現(xiàn)上還是有一些區(qū)別的:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-580822.html
- 對(duì)比粒度不同
- Vue 的虛擬 DOM 是Render 函數(shù)渲染生成的,對(duì)比粒度為組件級(jí)別。
- React 的虛擬 DOM 是由 React元素構(gòu)成,對(duì)比粒度為節(jié)點(diǎn)級(jí)別。
- 處理方式不同
- Vue 通過(guò)標(biāo)記靜態(tài)子樹(shù),可以重復(fù)使用不變的部分。
- React 總是重新構(gòu)造虛擬 DOM,對(duì)相同節(jié)點(diǎn)也會(huì)進(jìn)行屬性對(duì)比。
- 組件識(shí)別不同
- Vue 通過(guò)組件的 name 屬性識(shí)別組件是否相同。
- React 通過(guò)組件 type 來(lái)判斷是否為相同組件類(lèi)型。
- key 的作用不同
- Vue 主要用 key 管理可復(fù)用的元素。
- React 主要用 key 匹配舊元素與新元素。
- 事件處理不同
- Vue 可以精確知道哪個(gè)事件發(fā)生變化,只更新事件。
- React 每次都需要重新綁定事件,對(duì)組件影響較大。
綜上,Vue 和 React 雖然概念上都是通過(guò)虛擬 DOM + diff 實(shí)現(xiàn)增量更新,但在具體實(shí)現(xiàn)和優(yōu)化上還是有一定區(qū)別的。
到了這里,關(guān)于React、Vue框架如何實(shí)現(xiàn)組件更新,原理是什么?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!