- Vue3:以 effect 为中心的「依赖驱动」
- React:以 render + Hooks 为中心的「重执行驱动」
一、一句话对比(先立心智)
| 维度 | Vue3 | React |
|---|---|---|
| 核心单位 | effect(fn) | render(Component) |
| 更新模型 | 精确依赖触发 | 整函数重跑 |
| 响应式粒度 | 属性级 | 组件级 |
| 副作用调度 | scheduler | Scheduler + Fiber |
| 数据流 | pull(谁用谁收集) | push(setState 推) |
二、Vue3 effect
1️⃣ effect 的本质
ts
effect(() => {
console.log(state.count)
})发生了什么:
effect(fn)入栈(activeEffect)state.count→ gettertrack(target, key)- 建立 key → effect 的映射
txt
state.count
↓
Set(effect)2️⃣ 触发更新
ts
state.count++- setter
trigger(target, 'count')- 精确找到依赖 effect
- 执行 or scheduler(effect)
👉 不会影响没用到 count 的 effect
3️⃣ Vue effect 的核心优势
- 依赖自动收集
- 粒度极细
- effect ≠ render
- computed / watch 本质都是 effect
三、React Hooks:彻底不同的思路
1️⃣ React 的核心不是 Hook,是 render
jsx
function App() {
const [count, setCount] = useState(0)
return <div>{count}</div>
}⚠️ 重点:
组件函数本身 = render effect
2️⃣ setState 发生了什么
ts
setCount(1)- 创建 update
- 进入 Fiber updateQueue
- 调度 Scheduler
- 重新执行整个组件函数
txt
render(App)
├─ useState
├─ useEffect
├─ JSX👉 React 不知道你用没用 count 👉 它选择:我全跑一遍
3️⃣ Hooks 的本质
Hooks ≠ 响应式
ts
useState
useEffect
useMemo本质是:
ts
hook[i]- 靠 调用顺序
- 靠 Fiber.memoizedState
- 每次 render 顺序必须一致
四、依赖对比:自动 vs 手动(最本质差异)
Vue computed
ts
computed(() => a.value + b.value)- getter 中自动 track
- a / b 改 → 触发
React useMemo
ts
useMemo(() => a + b, [a, b])- 你手写依赖
- 写少了 = bug
- 写多了 = 性能问题
🧠 React 把控制权交给你
五、effect vs useEffect(名字相似,语义完全不同)
Vue effect | React useEffect | |
|---|---|---|
| 定位 | 响应式核心 | 副作用 Hook |
| 是否 render | ❌ | ❌ |
| 是否依赖收集 | ✅ 自动 | ❌ 手动 |
| 调度时机 | 同步 / 微任务 | commit 后 |
| 是否可嵌套 | ✅ | ❌ |
⚠️ 千万别把 useEffect 当 watch
六、调度模型对比(scheduler)
Vue
txt
setter → trigger → scheduler → jobQueue- effect 有 scheduler
- computed 是 lazy
- watch 可 flush sync / post
React
txt
setState
→ Scheduler(lane)
→ render(可中断)
→ commit(不可中断)- render 可被打断
- commit 一定完成
- 并发来自 Fiber
七、为什么 React 能并发,Vue 不强调?
Vue 的问题
- effect 粒度太细
- 依赖关系复杂
- 中断成本高
React 的选择
- 粗粒度 render
- render 可重跑
- 天然支持中断 / 重试
👉 这是 Fiber 的设计前提
八、闭包问题:Vue 几乎没有,React 到处都是
React 闭包陷阱
ts
useEffect(() => {
setInterval(() => {
console.log(count)
}, 1000)
}, [])👉 count 永远是初始值
Vue 不会
ts
watchEffect(() => {
console.log(count.value)
})九、源码级一一对应(核心对照)
| Vue3 | React |
|---|---|
effect | renderWithHooks |
track | 手写 deps |
trigger | dispatchAction |
| scheduler | Scheduler |
| Dep Map | Fiber.memoizedState |
十、总结
- Vue3 是“响应式引擎 + 编译器”
- React 是“可重跑的纯函数 + 调度系统”
不是谁更先进,是取舍不同。