面試官:說下 Vue 和 React 數(shù)據(jù)驅(qū)動原理的區(qū)別吧!
Hello,大家好,我是 Sunday。
昨天有位同學面試的時候被問到了:“說下 Vue 和 React 數(shù)據(jù)驅(qū)動原理的區(qū)別”。
所以今天咱們把這個問題說一下。
回答這種問題,我們可以采取 總分總 的方式,從以下四個層面進行描述:
- 數(shù)據(jù)驅(qū)動
- 數(shù)據(jù)追蹤的機制
- 數(shù)據(jù)流控制
- 數(shù)據(jù)更新機制
答案
React 和 Vue 都基于數(shù)據(jù)驅(qū)動的理念,也就是:當數(shù)據(jù)發(fā)生變化時,視圖自動更新。但是,他們在數(shù)據(jù)驅(qū)動的實現(xiàn)方式和概念是不同的。大致可以分為 4 點去說:
1. 數(shù)據(jù)驅(qū)動概念的核心思想
- React:React 的數(shù)據(jù)驅(qū)動依賴于不可變數(shù)據(jù)和單向數(shù)據(jù)流的思想。React 組件的狀態(tài)(state)是通過不可變的數(shù)據(jù)更新觸發(fā)重新渲染。組件的更新是通過“重新渲染整個組件樹”,而不是直接操作 DOM 元素。
- Vue:Vue 則采用響應式數(shù)據(jù)系統(tǒng),通過 Proxy(Vue 3)或 Object.defineProperty(Vue 2)來追蹤數(shù)據(jù)的變化,自動更新視圖。Vue 的數(shù)據(jù)驅(qū)動模型更接近于“聲明式”編程,開發(fā)者只需要修改數(shù)據(jù),Vue 的響應式系統(tǒng)會自動處理 DOM 更新。
2. 數(shù)據(jù)變化的追蹤機制
React: 手動觸發(fā)更新
- 在 React 中,數(shù)據(jù)變化通過顯式地更新 state 來驅(qū)動視圖更新。例如,使用 this.setState 或 useState 鉤子來改變組件的狀態(tài),然后 React 會根據(jù)更新后的狀態(tài)重新渲染組件。
- 不可變數(shù)據(jù):React 強調(diào)數(shù)據(jù)不可變,任何對數(shù)據(jù)的修改都需要返回一個新的對象,以便 React 識別狀態(tài)是否發(fā)生變化。React 通過淺比較來判斷組件是否需要更新。
示例:
function MyComponent() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
只有通過 setCount 才會觸發(fā)組件重新渲染。
Vue: 自動追蹤數(shù)據(jù)變化
- Vue 的數(shù)據(jù)變化是自動追蹤的。當數(shù)據(jù)被修改時,Vue 的響應式系統(tǒng)會立即追蹤到這個變化,并自動更新相應的視圖。Vue 的響應式系統(tǒng)會偵聽對象屬性的變化,通過 Proxy(Vue 3)或 Object.defineProperty(Vue 2)來劫持數(shù)據(jù)訪問和修改,從而實現(xiàn)數(shù)據(jù)與視圖的雙向綁定。
- 這種機制讓 Vue 的開發(fā)體驗更加簡潔,開發(fā)者不需要手動觸發(fā)視圖更新,只要修改數(shù)據(jù),視圖就會自動反映最新狀態(tài)。
示例:
<template>
<div>
<p>{{ count }}</p>
<button @click="increase">Increase</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0,
};
},
methods: {
increase() {
this.count += 1;
},
},
};
</script>
在 Vue 中,修改 this.count 就會觸發(fā)視圖更新,無需顯式調(diào)用渲染函數(shù)。
3. 數(shù)據(jù)流的控制
React: 單向數(shù)據(jù)流
- React 的數(shù)據(jù)流是單向的,即數(shù)據(jù)從父組件流向子組件,通過 props 進行傳遞。子組件不能直接修改父組件的數(shù)據(jù),而是通過回調(diào)函數(shù)讓父組件更新狀態(tài),這種設計簡化了數(shù)據(jù)流的管理,特別是在復雜應用中,保證了數(shù)據(jù)流的可控性和可預測性。
- 不可變性:React 提倡數(shù)據(jù)不可變,組件狀態(tài)或 props 發(fā)生變化時,會創(chuàng)建新的對象,并通過 setState 或 useState 重新渲染組件。
示例:
function Parent() {
const [count, setCount] = useState(0);
return <Child count={count} onIncrease={() => setCount(count + 1)} />;
}
function Child({ count, onIncrease }) {
return (
<div>
<p>{count}</p>
<button onClick={onIncrease}>Increase</button>
</div>
);
}
數(shù)據(jù)從 Parent 流向 Child,更新通過回調(diào)函數(shù)從 Child 傳回 Parent。
Vue: 雙向數(shù)據(jù)綁定和單向數(shù)據(jù)流
- Vue 提供了類似 React 的單向數(shù)據(jù)流,通過 props 將數(shù)據(jù)從父組件傳遞到子組件。子組件可以發(fā)出事件(如 $emit)通知父組件進行數(shù)據(jù)更新。
- 但是,Vue 還支持雙向數(shù)據(jù)綁定,尤其是在表單元素上,Vue 提供了 v-model 指令,可以實現(xiàn)數(shù)據(jù)的雙向綁定——即視圖中的數(shù)據(jù)變化會直接更新模型,模型數(shù)據(jù)變化也會自動反映在視圖上。這使得處理表單、輸入等場景更加簡單。
示例:單向數(shù)據(jù)流
<template>
<Child :count="count" @increase="increaseCount" />
</template>
<script>
export default {
data() {
return {
count: 0,
};
},
methods: {
increaseCount() {
this.count += 1;
},
},
};
</script>
示例:雙向數(shù)據(jù)綁定
<template>
<input v-model="name" />
</template>
<script>
export default {
data() {
return {
name: '',
};
},
};
</script>
通過 v-model,name 的變化會自動更新輸入框的內(nèi)容,輸入框內(nèi)容變化也會更新 name。
4. 數(shù)據(jù)更新與性能優(yōu)化
React: 虛擬 DOM + Reconciliation
- React 使用虛擬 DOM來管理視圖的更新。當組件的狀態(tài)或 props 發(fā)生變化時,React 會重新渲染虛擬 DOM 樹,并將其與之前的虛擬 DOM 進行對比(即 diff 過程)。React 通過 diff 算法找出變化的部分,并將這些部分應用到真實 DOM 中。
- 不可變數(shù)據(jù):由于 React 使用不可變數(shù)據(jù),React 可以通過淺比較來判斷數(shù)據(jù)是否發(fā)生了變化,從而減少不必要的更新。
Vue: 響應式系統(tǒng) + 模板編譯優(yōu)化
- Vue 的響應式系統(tǒng)可以自動追蹤數(shù)據(jù)變化,并只對發(fā)生變化的數(shù)據(jù)進行更新。通過響應式系統(tǒng),Vue 可以做到在數(shù)據(jù)層發(fā)生變化時,自動將變化反映到視圖層,而無需額外的 diff 比較。
- 模板編譯優(yōu)化:Vue 在編譯階段對模板進行分析,提取出靜態(tài)和動態(tài)部分,從而優(yōu)化渲染時的性能。靜態(tài)內(nèi)容只渲染一次,而動態(tài)內(nèi)容則通過響應式系統(tǒng)高效更新。
5. 總結
特性 | React | Vue |
數(shù)據(jù)追蹤機制 | 顯式通過 | 自動追蹤數(shù)據(jù)變化,基于 Proxy 實現(xiàn)響應式更新 |
數(shù)據(jù)流模式 | 單向數(shù)據(jù)流,父組件通過 props 傳遞數(shù)據(jù) | 單向數(shù)據(jù)流 + 雙向數(shù)據(jù)綁定, |
數(shù)據(jù)更新機制 | 不可變數(shù)據(jù),淺比較優(yōu)化性能 | 響應式系統(tǒng),自動偵聽數(shù)據(jù)變化 |
視圖更新策略 | 虛擬 DOM + diff 對比,找到最小更新集 | 模板編譯優(yōu)化 + 響應式系統(tǒng) |
性能優(yōu)化手段 | 應用不可變數(shù)據(jù)、 | 靜態(tài)內(nèi)容提升、Patch Flags(Vue 3)優(yōu)化更新 |
Vue 的數(shù)據(jù)驅(qū)動更加自動化和“聲明式”,而 React 則更依賴開發(fā)者顯式地控制狀態(tài)和數(shù)據(jù)流