面試必問:React和Vue各自是如何更新視圖的?
在 Vue 3 中,響應式系統是基于 Proxy
代理實現的,而 React 的狀態管理和更新機制則完全不同。React 并沒有使用 Proxy
,它主要依賴 狀態不可變性(Immutability) 和 調度(Reconciliation) 機制來觸發組件更新。
?? React 是如何實現狀態更新并觸發 UI 變化的?
1?? State 是不可變的
React 組件的 state
是不可變的,每次更新狀態時,我們并不會直接修改原來的 state,而是創建一個新的 state 對象,并用它替換舊的 state。例如:
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1); // 生成新的 state,觸發更新
};
React 通過 setState
或 useState
提供的 setCount
來觸發狀態更新。因為 count + 1
返回的是一個新的值,所以 React 認為狀態已變更。
2?? 觸發 Re-render
當 state
發生變化時,React 不會立即更新 UI,而是會:
- 觸發 調度(Scheduling),將當前組件標記為需要更新;
- 合并多個狀態更新,在下一次渲染時一起應用;
- 重新執行組件函數,得到新的
JSX
結構。
示例:
function Counter() {
const [count, setCount] = useState(0);
console.log("組件渲染了"); // 每次 state 更新時,組件都會重新執行
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
每次 setCount
觸發時,React 不會直接修改 DOM,而是會重新執行 Counter
組件函數,生成新的 JSX
,然后 React 通過 Diffing 算法 找出變化的地方,再進行高效的 DOM 更新。
3?? Diffing 和 Reconciliation 機制
當 state
發生變化時,React 并不會暴力重新渲染整個頁面,而是:
- 比較(Diffing)新舊 Virtual DOM,找出變化的部分;
- 高效更新(Reconciliation) 只修改受影響的 DOM 片段。
示例:
function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Hello</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
在 setCount(count + 1)
觸發后:
1.React 重新執行 App
組件,生成新的 Virtual DOM
:
<div>
<h1>Hello</h1>
<p>Count: 1</p> // 變化的地方
<button>Increment</button>
</div>
2.React 發現 h1
和 button
沒變,只更新 <p>
標簽的文本內容,而不是整個 div
。
4?? React 為什么不用 Proxy?
Vue 3 通過 Proxy
直接監聽對象的變化,實現細粒度的響應式,而 React 依賴 不可變數據 和 Virtual DOM: ? React 方案的優勢:
- 避免直接修改對象,防止副作用(確保狀態變更可預測)。
- 優化性能:通過
Diffing
機制減少不必要的 DOM 更新。 - 適用于函數式編程,配合
useState
,useReducer
等 hook 進行狀態管理。
? 缺點:
- 需要手動使用
setState
,不像 Vue 那樣直接修改對象就會自動觸發更新。 - 深層嵌套對象需要手動更新:
const [user, setUser] = useState({ name: "Alice", age: 25 });
setUser({ ...user, age: 26 }); // 不能直接 user.age = 26
- Vue 通過
Proxy
代理可以自動檢測到user.age = 26
的變化,而 React 需要創建新對象才能觸發更新。
?? 總結:React 如何更新 UI?
- 狀態不可變(Immutability):每次修改
state
時,必須創建新的對象或值。 - 組件重新執行:當
state
變化時,React 重新運行組件函數,返回新的JSX
結構。 - Diffing & Reconciliation:
- React 比較新舊
Virtual DOM
,找出變化的部分; - 只更新需要修改的 DOM 節點,而不是整個頁面。
?? 這就是 React 不用 Proxy
也能高效更新 UI 的關鍵!
Vue 3 的更新過程主要依賴 響應式系統(基于 Proxy
) 和 虛擬 DOM(Virtual DOM),它能夠高效地追蹤數據變化,并只更新需要修改的部分 DOM。下面詳細解析 Vue 3 的更新過程。
?? Vue 3 是如何觸發 UI 更新的?
1?? 響應式系統(Reactive System)
Vue 3 通過 Proxy
代理對象的 get
和 set
操作,實現自動追蹤依賴 & 觸發更新。當你修改 state
時,Vue 會:
- 追蹤數據(依賴收集)
- 檢測變化(觸發更新)
- 重新渲染 Virtual DOM 并更新真實 DOM
?? 示例:Vue 3 如何監聽數據變化
import { reactive } from "vue";
const state = reactive({ count: 0 });
console.log(state.count); // 訪問屬性時,Vue 記錄依賴
state.count++; // 修改屬性時,Vue 觸發更新
Vue 3 通過 Proxy
代理 state
,監聽 count
變化,自動通知視圖更新。
Vue 2 使用
Object.defineProperty()
只能監聽對象已有的屬性,Vue 3 的Proxy
解決了這個局限,支持監聽新增/刪除的屬性。
2?? 依賴收集(Dependency Collection)
Vue 需要知道哪些組件或計算屬性依賴 state.count
,這樣當 count
變化時,它只會更新受影響的組件,而不是整個應用。
工作流程:
- 當組件渲染時,Vue 訪問
state.count
,觸發get
,將該組件注冊為count
的依賴(收集副作用effect
)。 - 以后
count
變化時,Vue 會通知所有依賴它的地方更新。
示例:
import { reactive, effect } from "vue";
const state = reactive({ count: 0 });
// 創建一個副作用(Effect)
effect(() => {
console.log("Count changed:", state.count);
});
state.count++; // 修改時觸發 effect,打印 "Count changed: 1"
在 Vue 組件內部,effect()
由 Vue 自動管理,開發者無需手動調用。
3?? 觸發更新(Trigger & Scheduler)
當 state.count++
發生時,Vue 觸發 set
操作:
- Vue 先檢查
count
是否真的變化(新值 !== 舊值)。 - 如果變化了,Vue 通知
effect
(視圖更新邏輯)重新執行。 - Vue 使用 調度器(Scheduler) 合并多個狀態更新,避免不必要的重復渲染。
示例:多個狀態變化會合并更新
<script setup>
import { reactive } from "vue";
const state = reactive({ count: 0 });
function increment() {
state.count++;
state.count++; // Vue 不會觸發兩次 DOM 更新,而是合并優化
}
</script>
<template>
<p>{{ state.count }}</p>
<button @click="increment">+2</button>
</template>
Vue 通過 nextTick()
機制合并更新,減少 DOM 操作,提高性能。
4?? 重新渲染 Virtual DOM
當 state.count
變化后:
- Vue 重新執行組件的渲染函數,生成新的 Virtual DOM(虛擬 DOM) 結構。
- Vue 對比新舊 Virtual DOM(Diffing 算法),找出變化的部分。
- Vue 只更新變更的 DOM 節點,而不是整個頁面。
5?? Diffing & Patch 過程
Vue 3 使用 Patch Algorithm 進行高效的 DOM 更新:
- 如果 Virtual DOM 結構沒變(只是內容變了),Vue 直接更新文本內容。
- 如果子元素順序發生變化,Vue 采用最小修改策略,只移動必要的節點,而不是全部重繪。
示例:
<template>
<ul>
<li v-for="item in list" :key="item.id">{{ item.text }}</li>
</ul>
</template>
<script setup>
import { reactive } from "vue";
const list = reactive([
{ id: 1, text: "Vue" },
{ id: 2, text: "React" }
]);
setTimeout(() => {
list.reverse(); // Vue 只會調整 DOM 位置,而不會重新創建 <li>
}, 2000);
</script>
Vue 只移動 <li>
位置,而不會銷毀 & 重新創建整個列表。
?? Vue 3 的 UI 更新完整流程
1?? 訪問響應式數據(Proxy get
) → 觸發依賴收集
2?? 數據變更(Proxy set
) → 觸發更新(Effect 重新執行)
3?? Vue 重新執行渲染函數,生成新的 Virtual DOM
4?? Vue 進行 Diffing,找出變更的 DOM 節點
5?? Vue 使用 Patch 機制,僅更新需要修改的部分 DOM
相比 Vue 2,Vue 3 在依賴追蹤、調度和 Virtual DOM 更新上更高效!
?? Vue 3 和 React 更新機制對比
特性 | Vue 3 | React |
響應式原理 |
代理數據,自動追蹤依賴 |
/ |
依賴收集 | 訪問數據時自動收集( | 組件渲染時自動關聯 state |
狀態變更 |
操作觸發更新 |
觸發更新 |
組件更新機制 | 重新運行 渲染函數 生成 VDOM | 重新執行 組件函數 生成 VDOM |
Diff 算法 | 只更新變化的部分 | 只更新變化的部分 |
批量更新 |
自動合并 | React 事件中 |
?? Vue 3 的 Proxy 監聽數據變更,React 通過 useState
返回新對象。Vue 自動追蹤依賴,而 React 需要手動 setState
。
?? 總結:Vue 3 是如何更新界面的?
- Proxy 監聽數據變化,訪問數據時自動收集依賴,修改數據時自動觸發更新。
- 依賴收集(Effect 機制),組件只會在需要更新時重新渲染,而不會整個應用重繪。
- 批量更新(Scheduler),合并多個
setState
操作,減少不必要的渲染。 - Diffing & Patch 機制,Vue 只更新最小范圍的 DOM,而不是整個頁面。
?? Vue 3 更新機制的核心優勢
? 更精準的依賴追蹤:基于 Proxy
,比 Vue 2 更高效,支持監聽新增/刪除屬性? 更少的渲染開銷:只有真正變化的組件才會重新渲染? 更高效的 DOM 更新:使用 Diff 算法 & Patch 機制,只更新必要部分
Vue 3 結合了響應式系統 + Virtual DOM,讓 UI 更新更智能、更高效。希望這個解析對你理解 Vue 3 的更新機制有幫助!