React 开发者学 Vue3:Composition API 核心用法对照与避坑实录


一、前言:Vue3 Composition API 是 Vue 开发的新范式

如果你是 React 开发者,Vue3 的 Composition API 会让你感到既熟悉又陌生。本文从 React 开发者视角,逐一对照 Hooks 与 Composition API 的核心用法,帮你快速上手并避开常见坑。


二、核心概念对照

2.1 状态管理:useState vs ref/reactive

tsx 复制代码
// React
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: '', age: 0 });
setCount(prev => prev + 1);
setUser(prev => ({ ...prev, name: 'Tom' }));
ts 复制代码
// Vue3
const count = ref(0);
const user = reactive({ name: '', age: 0 });
count.value++;
user.name = 'Tom'; // 直接赋值,不需要 setState

关键差异 :Vue3 的 reactive 对象可以直接修改属性,无需 immer 或 spread 语法。ref 基础类型需要 .value,在模板中自动解包。


2.2 副作用:useEffect vs watchEffect/watch

tsx 复制代码
// React
useEffect(() => {
  document.title = `${count} times clicked`;
  return () => {
    // 清理副作用
  };
}, [count]);
ts 复制代码
// Vue3
watchEffect(() => {
  document.title = `${count.value} times clicked`;
  // 返回清理函数
  return () => { /* cleanup */ };
});

// 精确监听
watch(count, (newVal, oldVal) => {
  console.log(`${oldVal} → ${newVal}`);
});

关键差异 :Vue3 的 watchEffect 自动追踪依赖,不需要手写依赖数组。watch 精确监听,类似 useEffect 指定 deps。


2.3 计算属性:useMemo vs computed

tsx 复制代码
// React
const doubleCount = useMemo(() => count * 2, [count]);
ts 复制代码
// Vue3
const doubleCount = computed(() => count.value * 2);
// doubleCount.value 是只读的,依赖变化时自动更新

关键差异 :Vue3 的 computed 天然缓存,不需要手动写 deps,访问 .value 即得最新值。


三、生命周期对照

React Hook Vue3 Composition 时机
无(构造函数) setup() 本身 组件初始化
useEffect(fn, []) onMounted(fn) DOM 挂载后
useEffect(() => fn, []) onUnmounted(fn) 组件卸载
useEffect(fn, [dep]) watch/watchEffect 依赖变化
onUpdated(fn) 每次更新后
ts 复制代码
// Vue3 生命周期示例
import { onMounted, onUnmounted, onUpdated } from 'vue';

export function useEventListener(event: string, handler: Function) {
  onMounted(() => window.addEventListener(event, handler as EventListener));
  onUnmounted(() => window.removeEventListener(event, handler as EventListener));
}

四、组合式函数(类比 React 自定义 Hooks)

tsx 复制代码
// React 自定义 Hook
function useWindowSize() {
  const [size, setSize] = useState({ width: 0, height: 0 });
  useEffect(() => {
    const handler = () => setSize({ width: window.innerWidth, height: window.innerHeight });
    window.addEventListener('resize', handler);
    handler();
    return () => window.removeEventListener('resize', handler);
  }, []);
  return size;
}
ts 复制代码
// Vue3 组合式函数(Composable)
export function useWindowSize() {
  const width = ref(window.innerWidth);
  const height = ref(window.innerHeight);

  const handler = () => {
    width.value = window.innerWidth;
    height.value = window.innerHeight;
  };

  onMounted(() => window.addEventListener('resize', handler));
  onUnmounted(() => window.removeEventListener('resize', handler));

  return { width, height };
}

// 使用
const { width, height } = useWindowSize();

五、常见坑点

坑1:解构 reactive 对象失去响应性

ts 复制代码
// ❌ 错误:解构后 name 不再是响应式的
const { name } = reactive({ name: 'Tom' });

// ✅ 正确:用 toRefs 保持响应性
const state = reactive({ name: 'Tom', age: 18 });
const { name, age } = toRefs(state);

坑2:ref 在模板里不需要 .value,但在 JS 里需要

ts 复制代码
const count = ref(0);
// 模板中:{{ count }}  ← 自动解包,不用 .value
// JS中:count.value++  ← 必须 .value

坑3:watch 默认不立即执行

ts 复制代码
// React useEffect 会在 mount 时立即执行
useEffect(() => { fetchData(); }, [userId]);

// Vue3 watch 默认不立即执行,需要加 immediate: true
watch(userId, fetchData, { immediate: true });
// 或者用 watchEffect(总是立即执行)
watchEffect(() => fetchData(userId.value));

六、总结:从 React 迁移的心智模型

  1. ref/reactive 替代 useState,reactive 对象可以直接修改,无需 setState
  2. watchEffect/watch 替代 useEffect,自动追踪依赖,无需 deps 数组
  3. computed 替代 useMemo,天然缓存,语法更简洁
  4. Composables 替代自定义 Hooks,结构和写法几乎一致
  5. 最大不同:Vue3 用 Proxy 追踪依赖,响应式是自动的;React 需要手动声明 deps

💬 关注我,React↔Vue3 迁移避坑系列持续更新,帮你平滑过渡!


💬 觉得有用?点赞+收藏+关注! 后续持续更新《框架迁移避坑》系列,React↔Vue3↔Angular 全覆盖。

标签:react | vue3 | compositionapi | 前端 | 对比 | 避坑

相关推荐
xinzheng新政2 小时前
Javascript·深入学习基础知识2
开发语言·javascript·学习
之歆3 小时前
Composition API 深度解析 - 重新理解 Vue 的组件化编程
前端·javascript·vue.js
Cxiaomu3 小时前
React Native 双端一体工程,如何实现分端运行与分端打包?
javascript·react native·react.js
冰暮流星3 小时前
javascript之dom访问属性
开发语言·javascript·dubbo
一只小阿乐3 小时前
TypeScript中的React开发
前端·javascript·typescript·react
Highcharts.js4 小时前
Highcharts客户端导出使用文档说明|图表导出模块讲解
前端·javascript·pdf·highcharts·图表导出
华仔啊4 小时前
GitHub 25k Star!这款开源录屏工具,免费无水印可商用,彻底告别付费
javascript
一只小阿乐4 小时前
react路由中使用context
前端·javascript·react.js·context 上下文
Hilaku4 小时前
一周狂揽40K+ Star⭐ 的 Pretext 到底有多变态?
前端·javascript·html