React和Vue組件更新的實(shí)現(xiàn)及區(qū)別
引言
React 和 Vue 都是當(dāng)今最流行的前端框架,它們都實(shí)現(xiàn)了組件化開發(fā)模式。為了優(yōu)化性能,兩者都采用了虛擬DOM技術(shù)。當(dāng)組件狀態(tài)發(fā)生改變時(shí),它們會使用虛擬DOM進(jìn)行局部渲染比對,只更新必要的DOM節(jié)點(diǎn),從而避免重新渲染整個(gè)組件樹。本文將從React和Vue的組件更新原理入手,剖析兩者虛擬DOM difer算法的異同點(diǎn)。React通過comparing virtual DOM components and re-rendering only difference,而Vue通過響應(yīng)式依賴追蹤確定組件invalidated狀態(tài)。盡管兩者技術(shù)實(shí)現(xiàn)不同,但目的都是實(shí)現(xiàn)增量更新提高性能。本文還將通過代碼實(shí)例,說明兩者的Domin difer流程、對比粒度、更新觸發(fā)等關(guān)鍵區(qū)別。讀者將對React和Vue增量更新的內(nèi)在原理有更深的理解,學(xué)會在實(shí)踐中根據(jù)應(yīng)用場景選擇更合適的框架。
React、Vue如何實(shí)現(xiàn)組件更新
React和Vue是兩個(gè)流行的JavaScript庫,用于構(gòu)建用戶界面。它們都有自己的組件,下面將簡單介紹一下更新原理。
React的組件更新機(jī)制:
在React中,組件更新是由虛擬DOM(Virtual DOM)和diff算法驅(qū)動的。當(dāng)組件的狀態(tài)(state)或?qū)傩裕╬rops)發(fā)生變化時(shí),React會進(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通過最小化DOM操作,只更新需要變化的部分到實(shí)際的DOM。
- 組件更新完成,觸發(fā)相應(yīng)的生命周期方法(如
componentDidUpdate
)。
下面是一個(gè)簡單的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
方法會更新組件的狀態(tài)count
。React會重新調(diào)用render()
方法重新渲染虛擬DOM,并將新的虛擬DOM與舊的虛擬DOM進(jìn)行比較,然后只更新變化的部分(這里是<p>Count: {this.state.count}</p>
)到實(shí)際的DOM。
Vue的組件更新機(jī)制:
在Vue中,組件更新是由響應(yīng)式系統(tǒng)驅(qū)動的。Vue使用了一種名為"依賴追蹤"的機(jī)制,它會在組件渲染過程中追蹤組件所依賴的數(shù)據(jù),并建立起依賴關(guān)系。當(dāng)依賴的數(shù)據(jù)發(fā)生變化時(shí),Vue會通知相關(guān)的組件進(jìn)行更新。
Vue的更新過程大致如下:
- 數(shù)據(jù)變化時(shí),setter 觸發(fā)依賴,標(biāo)記組件為臟數(shù)據(jù)
- 在下一輪事件循環(huán)中,Vue 會調(diào)用 patch 函數(shù),比對新舊虛擬 DOM 樹
- 通過 diff 算法比較樹的差異,得到需要更新的最小節(jié)點(diǎn)
- 只對變化的部分進(jìn)行 DOM 操作,更新視圖
diff 算法的主要步驟是:
- 對比新舊節(jié)點(diǎn),是否為同一節(jié)點(diǎn)
- 如果不是,直接替換該節(jié)點(diǎn)及子節(jié)點(diǎn)
- 如果是,對比新舊節(jié)點(diǎn)的屬性是否變化
- 對比子節(jié)點(diǎn),使用鍵值優(yōu)化順序復(fù)雜度
- 遞歸對比所有子節(jié)點(diǎn)
通過這種方式,Vue 可以只更新變化的部分,避免不必要的 DOM 操作。
下面是一個(gè)簡單的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
方法會更新組件的數(shù)據(jù)count
。Vue會檢測到count
的變化,并通知組件重新渲染。然后Vue使用虛擬DOM進(jìn)行比較,只更新變化的部分(這里是<p>Count: {{ count }}</p>
)到實(shí)際的DOM。
總結(jié):
React和Vue都采用了類似的組件更新機(jī)制,它們都通過比較虛擬DOM或追蹤依賴來實(shí)現(xiàn)高效的組件更新。React和Vue都使用虛擬DOM和diff算法,這些機(jī)制使得組件的更新變得高效,只更新必要的部分,提高了應(yīng)用的性能。
React與Vue更新的區(qū)別
Vue
- 使用數(shù)據(jù)響應(yīng)系統(tǒng),通過改變組件的數(shù)據(jù)屬性來觸發(fā)更新。
- 當(dāng)組件的 data、props、computed 等屬性改變時(shí),會觸發(fā) setter,標(biāo)記組件為“臟”。
- 在下一輪事件循環(huán)中,會批量觸發(fā)這些“臟”組件的重新渲染。
React
- 使用狀態(tài)(state)和屬性(props)來控制組件。
- 當(dāng)狀態(tài)或?qū)傩愿淖儠r(shí),會觸發(fā)重新渲染。
- React 使用 Virtual DOM 來提高性能,只會針對改變的組件進(jìn)行最小化渲染。
相同點(diǎn) - 兩者都是聲明式框架,通過狀態(tài)/數(shù)據(jù)變化控制界面。
- 都使用虛擬 DOM ,進(jìn)行增量更新提高性能。
區(qū)別 - Vue 側(cè)重響應(yīng)式數(shù)據(jù),React 更側(cè)重狀態(tài)管理。
- Vue 使用模板,React 使用 JSX。
- Vue 批量異步更新,React 同步更新。
- Vue 依賴數(shù)據(jù)變化觸發(fā)更新,React 通過 setState/useState 控制。
總體來說,兩者都使用了類似的虛擬DOM和增量更新機(jī)制,但在觸發(fā)更新的方式上有差異。Vue 更加主動,而 React 更加顯式地控制。
什么是Diff算法
diff 算法是虛擬 DOM 中用于增量更新的關(guān)鍵算法。它的主要作用是對比兩棵虛擬 DOM 樹的差異,運(yùn)算出需要更新的最小量 DOM 操作。
diff 算法的基本步驟如下:
- 用虛擬 DOM 構(gòu)建出新的DOM樹(樹A)
- 將新的DOM樹與舊的DOM樹(樹B)進(jìn)行對比找出差異
- 對比過程中,首先比較樹A和樹B的根節(jié)點(diǎn)
- 如果根節(jié)點(diǎn)不相同,直接替換整個(gè)DOM樹
- 如果根節(jié)點(diǎn)相同,再遞歸地對比和更新它的屬性、子節(jié)點(diǎn)等
- 只更新變化的部分,不修改相同的節(jié)點(diǎn)
- 最后將變化渲染到真實(shí)DOM中
diff算法的時(shí)間復(fù)雜度為O(n),它通過以下優(yōu)化進(jìn)一步提升了性能:
- Web UI中DOM節(jié)點(diǎn)跨層級的移動操作特別少,可以忽略不計(jì)
- 擁有相同類的兩個(gè)組件生成相似的樹形結(jié)構(gòu),擁有較高的移位率
- 通過唯一id區(qū)分節(jié)點(diǎn),可以根據(jù)id直接判斷兩個(gè)節(jié)點(diǎn)是否相同
這里是一個(gè)簡化的React Diff算法的實(shí)現(xiàn)示例。它包含了比較根節(jié)點(diǎn)、屬性和子節(jié)點(diǎn)的邏輯。當(dāng)根節(jié)點(diǎn)類型不同時(shí),創(chuàng)建新節(jié)點(diǎn)并替換舊節(jié)點(diǎn)。當(dāng)屬性不同時(shí),更新屬性。對于子節(jié)點(diǎn),通過遍歷舊子節(jié)點(diǎn)和新子節(jié)點(diǎn)來進(jìn)行比較,并進(jìn)行遞歸的Diff算法調(diào)用。根據(jù)比較結(jié)果,進(jìn)行增加、刪除或更新相應(yīng)的節(jié)點(diǎn)。
// 舊的虛擬DOM樹 let oldVDOM = { tag: 'div', attrs: { id: 'container' }, children: [ {tag: 'p', attrs: {class: 'paragraph'}}, {tag: 'span', attrs: {class: 'span'}} ] } // 新的虛擬DOM樹 let newVDOM = { tag: 'div', attrs: { id: 'container' }, children: [ {tag: 'p', attrs: {class: 'paragraph'}}, {tag: 'span', attrs: {class: 'span-new'}} // span類名變化 ] } // diff算法 function diff(oldTree, newTree) { // 1. 比較根節(jié)點(diǎn) if(oldTree.tag !== newTree.tag) { // 根節(jié)點(diǎn)不同,返回新樹 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) // 深度遞歸對比子節(jié)點(diǎn) const changedChild = diff(child, newChild) childChanges.push(changedChild) }) newTree.children = childChanges return newTree } // 最終只會更新 span 的類名變化 const newVDOM = diff(oldVDOM, newVDOM)
兩者的diff算法的區(qū)別
Vue 和 React 雖然都采用了虛擬 DOM 和 diff 算法,但在具體的 diff 實(shí)現(xiàn)上還是有一些區(qū)別的:
- 對比粒度不同
- Vue 的虛擬 DOM 是Render 函數(shù)渲染生成的,對比粒度為組件級別。
- React 的虛擬 DOM 是由 React元素構(gòu)成,對比粒度為節(jié)點(diǎn)級別。
- 處理方式不同
- Vue 通過標(biāo)記靜態(tài)子樹,可以重復(fù)使用不變的部分。
- React 總是重新構(gòu)造虛擬 DOM,對相同節(jié)點(diǎn)也會進(jìn)行屬性對比。
- 組件識別不同
- Vue 通過組件的 name 屬性識別組件是否相同。
- React 通過組件 type 來判斷是否為相同組件類型。
- key 的作用不同
- Vue 主要用 key 管理可復(fù)用的元素。
- React 主要用 key 匹配舊元素與新元素。
- 事件處理不同
- Vue 可以精確知道哪個(gè)事件發(fā)生變化,只更新事件。
- React 每次都需要重新綁定事件,對組件影響較大。
綜上,Vue 和 React 雖然概念上都是通過虛擬 DOM + diff 實(shí)現(xiàn)增量更新,但在具體實(shí)現(xiàn)和優(yōu)化上還是有一定區(qū)別的。
到此這篇關(guān)于React和Vue組件更新的實(shí)現(xiàn)及區(qū)別的文章就介紹到這了,更多相關(guān)React和Vue框架組件更新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React+Typescript項(xiàng)目環(huán)境搭建并使用redux環(huán)境的詳細(xì)過程
這篇文章主要介紹了React+Typescript項(xiàng)目環(huán)境搭建并使用redux環(huán)境的詳細(xì)過程,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09React18+TS通用后臺管理系統(tǒng)解決方案落地實(shí)戰(zhàn)示例
這篇文章主要為大家介紹了React18+TS通用后臺管理系統(tǒng)解決方案落地實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08React Fiber結(jié)構(gòu)的創(chuàng)建步驟
這篇文章主要介紹了React Fiber結(jié)構(gòu)的創(chuàng)建步驟,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下2021-04-04React使用Props實(shí)現(xiàn)父組件向子組件傳值
在React中,組件之間的數(shù)據(jù)傳遞通常是通過屬性(Props)來實(shí)現(xiàn)的,父組件可以通過屬性向子組件傳遞數(shù)據(jù),這是React組件通信的基礎(chǔ)模式之一,本文將探討如何使用Props來實(shí)現(xiàn)父組件向子組件傳遞數(shù)據(jù),需要的朋友可以參考下2025-04-04React函數(shù)式組件Hook中的useEffect函數(shù)的詳細(xì)解析
useEffect是react v16.8新引入的特性。我們可以把useEffect hook看作是componentDidMount、componentDidUpdate、componentWillUnmounrt三個(gè)函數(shù)的組合2022-10-10