Vue3转React速查表

  • Vue : 基于可变数据 (Mutable) + 自动依赖追踪 (响应式系统)。
  • React : 基于不可变数据 (Immutable) + 显式依赖数组 (手动触发更新)。

1. 核心概念映射表 (Cheat Sheet)

| 功能 | Vue 3 (Composition API) | React (Hooks) | 关键差异点 |

| :--- | :--- | :--- | : |

| 状态定义 | const count = ref(0) | const [count, setCount] = useState(0) | Vue 直接修改 count.value;React 必须调用 setCount |

| 计算属性 | const double = computed(() => count.value * 2) | const double = useMemo(() => count * 2, [count]) | React 需手动指定依赖 [count] |

| 副作用 | watchEffect(() => { ... })
watch(source, cb) | useEffect(() => { ... }, [deps]) | React 的 useEffect 同时涵盖 mount/update/unmount |

| 清理副作用 | onUnmounted(() => ...)

(在 watch 中 return) | useEffect(() => { return () => ... }, []) | 清理函数在 return 中返回 |

| 模板/JSX | <template>{``{ count }}</template> | return <div>{count}</div> | React 直接用 JS 表达式,无插值符号 {``{ }} |

| 条件渲染 | v-if="isOk" | { isOk && <div>...</div> } | React 使用逻辑与运算符或三元表达式 |

| 列表渲染 | v-for="item in list" :key="item.id" | {list.map(item => <div key={item.id}>)} | React 必须显式写 mapkey |

| 事件绑定 | @click="handleClick" | onClick={handleClick} | React 用驼峰 onClick,传函数引用 (不调用) |

| 双向绑定 | v-model="text" | value={text} onChange={(e) => setText(e.target.value)} | React 没有内置指令,需手动绑定 value + onChange |

| 组件通信 | props, emit('event') | props, callback props | React 单向数据流,子传父通过回调函数 |

| 插槽 | <slot />, <slot name="header"> | props.children, props.header | React 把插槽当作 props 传递 (通常是 children) |

| 生命周期 | onMounted, onUpdated | useEffect(..., []) (Mount)
useEffect(..., [deps]) (Update) | React 将生命周期合并进 useEffect |

| 样式绑定 | :class="{ active: isActive }" | className={isActive ? 'active' : ''} | React 用 className,逻辑需用 JS 三元或库 (clsx) |

| Refs/DOM | const el = ref(null)
<div ref="el"> | const el = useRef(null)
<div ref={el}> | Vue ref 取值 .value;React ref 取值 .current |

2. 代码实战对比 (Side-by-Side)

场景 A: 基础计数器 (State & Events)
Vue 3:
javascript 复制代码
<script setup>
import { ref } from 'vue';

const count = ref(0);
const increment = () => count.value++;
</script>

<template>
  <button @click="increment">Count: {{ count }}</button>
</template>
React:
javascript 复制代码
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  const increment = () => setCount(prev => prev + 1); // 习惯用函数式更新

  return (
    <button onClick={increment}>Count: {count}</button>
  );
}

注意 : React 中事件处理函数不要加括号 (),除非你需要传参(此时用箭头函数包裹)。

场景 B: 异步数据获取 (Effects)
Vue 3:
javascript 复制代码
<script setup>
import { ref, onMounted } from 'vue';

const data = ref(null);
const loading = ref(false);

const fetchData = async () => {
  loading.value = true;
  data.value = await fetch('/api').then(r => r.json());
  loading.value = false;
};

onMounted(fetchData);
</script>
React:
javascript 复制代码
import { useState, useEffect } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let isMounted = true; // 防止组件卸载后更新状态
    
    const fetchData = async () => {
      setLoading(true);
      const res = await fetch('/api');
      const json = await res.json();
      if (isMounted) setData(json);
      setLoading(false);
    };

    fetchData();

    // 清理函数 (对应 onUnmounted)
    return () => { isMounted = false; };
  }, []); // 空依赖数组 = 只在挂载时运行

  return <div>{loading ? 'Loading...' : JSON.stringify(data)}</div>;
}
场景 C: 父子组件通信 (Props & Callbacks)
Vue 3:
javascript 复制代码
<!-- Child.vue -->
<script setup>
defineProps(['msg']);
const emit = defineEmits(['update']);
</script>
<template>
  <button @click="emit('update', 'new value')">{{ msg }}</button>
</template>
React:
javascript 复制代码
// Child.jsx
function Child({ msg, onUpdate }) {
  return (
    <button onClick={() => onUpdate('new value')}>{msg}</button>
  );
}

// Parent.jsx
<Child msg="Hello" onUpdate={(val) => console.log(val)} />

关键点 : React 没有 $emit。父组件传递一个函数作为 prop,子组件调用该函数。

场景 D: 列表与条件渲染
Vue 3:
javascript 复制代码
<template>
  <ul v-if="items.length">
    <li v-for="item in items" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
  <p v-else>No items</p>
</template>
React:
javascript 复制代码
return (
  <>
    {items.length > 0 ? (
      <ul>
        {items.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    ) : (
      <p>No items</p>
    )}
  </>
);

技巧 : 推荐使用 clsxclassnames 库来处理复杂的 class 拼接,替代 Vue 的对象语法。

3. 生态库迁移指南 (Vue -> React)

类别 Vue 3 生态 React 推荐生态 (2026标准) 备注
路由 Vue Router React Router v6/v7 或 Next.js App Router Next.js 是首选,内置路由
状态管理 Pinia / Vuex Zustand (最流行), Redux Toolkit, Jotai Zustand 最像 Pinia,简单无样板
HTTP Axios / VueUse TanStack Query (React Query), Axios React Query 是服务端状态管理的神器
表单 VeeValidate / FormKit React Hook Form, Zod (校验) React Hook Form 性能极佳
UI 组件库 Element Plus / AntDV Ant Design, MUI, Shadcn/ui (最火) Shadcn/ui 是复制代码而非安装包,极度灵活
工具函数 VueUse Lodash, date-fns, clsx React 没有官方工具集,社区组合使用
CSS 方案 Scoped CSS / SCSS Tailwind CSS (主流), CSS Modules, Styled-components Tailwind 在 React 生态中占据统治地位

4. 避坑指南:Vue 开发者转 React 的常见错误

  1. 直接修改 State
    • Vue: count.value++
    • React: count++ ❌ (不会触发重渲染)
    • React: setCount(count + 1)
  2. 在 Render 函数中执行副作用
    • 不要在组件函数体直接写 fetch()console.log('render') (除非受控),这会导致无限循环。必须放在 useEffect 中。
  3. 依赖数组遗漏 ⚠️
    • Vue 自动追踪依赖。
    • React 必须手动在 useEffectuseMemo[] 中列出所有用到的变量,否则会遇到"闭包陷阱"(拿到旧值)。
  4. Key 的使用 ⚠️
    • Vue 有时不写 key 也能跑。
    • React 必须map 生成的列表提供稳定的 key (不要用 index,除非列表静态)。
  5. Ref 的取值 ⚠️
    • Vue: myRef.value
    • React: myRef.current (且修改 ref.current 不会触发重渲染,它用于存储可变但不需要视图更新的值)。
相关推荐
@PHARAOH2 小时前
WHAT - 替代 Express 和 Koa 的现代轻量版 Hono
前端·微服务·express·koa
badhope2 小时前
Python、C、Java 终极对决!谁主沉浮?谁将消亡?
java·c语言·开发语言·javascript·人工智能·python·github
掘金安东尼2 小时前
低代码真的能替代前端吗?我看了 RollCode 的设计之后有点新想法
前端
IT_陈寒2 小时前
JavaScript开发者必知的5个高效调试技巧,比console.log强10倍!
前端·人工智能·后端
亿元程序员2 小时前
历时100天,亿元Cocos小游戏实战合集顺利完结!!!
前端
早點睡3902 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-linear-gradient-text
javascript·react native·react.js
恋猫de小郭2 小时前
Flutter Beta 版本引入 ScrollCacheExtent ,并修复长久存在的 shrinkWrap NaN 问题
android·前端·flutter
Liu.7742 小时前
vscode前端实用插件
前端·vscode
放逐者-保持本心,方可放逐3 小时前
地图 热力图核心封装
javascript·cpu·gpu·热力图·cesium·核心渲染判断·渲染管线优化