正文
1.核心原理
Vue
中的watch
、watchEffect
是基于Vue
的响应式系统(Proxy
),依赖于ref
或reactive
数据的变化。React
中的useEffect
基于状态驱动的重新渲染机制,通过依赖数组[dependency]
,手动声明需要追踪的状态或属性。
2.功能
Vue
中的watch
:
- 专门用于监听指定响应式数据或计算属性的变化。
- 回调函数提供两个参数:新值和旧值。
- 常用于对特定数据的精准监听,比如异步操作、深度监听对象等。
watch(data, (newVal, oldVal) => {console.log('Data changed:', oldVal, '->', newVal); });
Vue
中的watchEffect
:
- 不需要手动声明依赖,简单高效,但依赖关系可能不够直观。
- 适用于简单副作用场景,例如动态计算或直接响应所有相关数据变化。
- vue响应是同步的,所以在watchEffect中async/await后面的异步代码中的依赖无法收集
watchEffect(() => {console.log(state.value); // 自动将 state.value 加入依赖 });
React
中的useEffect
:
- 用于处理组件生命周期相关的副作用(如数据订阅、DOM 操作等)。
- 通过依赖数组
[dependency]
显式声明监听的依赖项。 - 可以清理副作用,通过返回一个函数来卸载或清理资源。
useEffect(() => {console.log('Dependency changed'); }, [dependency]);
3.依赖追踪方式
Vue
- 自动依赖追踪(
watchEffect
):- Vue 的响应式系统会动态追踪函数内部使用的所有响应式数据。
- 例如:
watchEffect(() => {console.log(state.value); // 自动将 state.value 加入依赖 });
- 原理:当
state.value
被读取时,Vue 的依赖追踪器(基于Dep
)会将当前副作用函数与该属性绑定。
- 显式依赖声明(
watch
):- 依赖由开发者显式指定:
watch(() => state.value, (newVal) => {console.log(newVal); });
- 原理:通过 getter 函数,明确指定哪些响应式数据需要触发回调。
- 依赖由开发者显式指定:
React
- 显式依赖声明:
- React 中依赖需要手动指定,React 不会动态追踪状态使用。
- 例如:
useEffect(() => {console.log('State value changed:', state.value); }, [state.value]);
- 原理:React 比较依赖数组中的值(通过浅比较)。只有依赖值发生变化时,
useEffect
才会重新执行。
4.总结
特性 | Vue `watch` | Vue `watchEffect` | React `useEffect` |
---|---|---|---|
依赖声明方式 | 手动指定 | 自动追踪 | 手动指定 |
执行时机 | 数据变化后 | 初始化 & 数据变化后 | DOM 渲染后 |
适用场景 | 复杂依赖、多数据监听 | 简单自动副作用 | DOM 操作、副作用逻辑 |
优化难度 | 低 | 低 | 中(需手动优化依赖) |
拓展
Vue和React响应式比较
Vue 3
- 基于 Proxy 的响应式系统:
- Vue 3 使用 JavaScript 的
Proxy
对象拦截对数据的访问和修改,实现响应式。 - 数据的依赖关系通过 “依赖收集” 的方式自动建立,变化时会触发对应的渲染更新。
- 响应式系统直接作用于数据层,开发者操作的普通对象会自动变成响应式。
- Vue 3 使用 JavaScript 的
React 18
- 基于 Virtual DOM 和调度器:
- React 的响应式以状态管理为核心,借助
useState
和useReducer
等钩子函数实现状态的更新和追踪。 - 状态变更会触发组件的重新渲染,并通过虚拟 DOM 比对(Diff 算法)计算出需要更新的部分,再应用到真实 DOM。
- React 的响应式以状态管理为核心,借助
特性 | Vue 3 | React 18 |
---|---|---|
响应式核心 | Proxy + 自动依赖追踪 | 状态驱动 + 显式依赖管理 |
依赖追踪 | 自动化、精确到属性级别 | 依赖数组显式声明 |
状态管理 | 响应式对象直接修改触发更新 | `useState` / `useReducer` 显式管理 |
渲染机制 | 精确到数据属性的更新 | 组件级渲染,通过虚拟 DOM 优化 |
性能优化 | 自动依赖追踪 + 批量更新 | 并发模式 + 虚拟 DOM 优化 |
使用复杂度 | 简单易用,自动化高 | 灵活性高,需手动优化 |
失去响应性
Vue
直接使用count.data
是错误的,因为这个时候count.data
被解构成了一个普通值,不再具有响应性。
//正确写法
watch(()=>count.data, (newValue, oldValue) => {console.log(newValue, oldValue);
});//错误写法
watch(count.data, (newValue, oldValue) => {console.log(newValue, oldValue);
});
React
React的响应性与Vue不同,React 更倾向于显式依赖声明,而 Vue 依赖于响应式系统,这里的count.data
是一个普通变量,而只有setCount
才能触发useEffect
的监听
//正确写法
const [count, setCount] = useState({ data: 0 });
useEffect(() => {console.log('count.data changed:', count.data);
}, [count.data]);//错误写法
const count = { data: 0 };
useEffect(() => {console.log('count.data changed:', count.data);
}, [count.data]);