从 Vue 转到 React 并不难,两者作为主流前端框架,核心思想(组件化、声明式编程)一致,但在语法、API 设计和最佳实践上存在差异。下面从核心概念、语法差异、关键特性到实战技巧,帮你快速上手 React。

一、核心思想对比:理解「差异根源」

维度VueReact
设计理念渐进式框架,强调「模板与逻辑分离」函数式理念,强调「UI = 函数(状态)」,逻辑与 UI 通过 JS 结合
核心范式基于「模板语法 + 选项式 API」(Vue 2)或「组合式 API」(Vue 3)基于「JSX + 函数组件 + Hooks」,一切皆 JavaScript
状态驱动双向绑定(v-model)+ 响应式系统自动追踪依赖单向数据流,通过「状态更新触发重新渲染」实现响应式
灵活性内置解决方案更完善(如模板指令、scoped 样式)更灵活,需自行选择生态工具(如样式方案、状态库)

二、语法差异:从「模板」到「JSX」

Vue 用 template 模板语法,React 用 JSX(JavaScript XML),这是最直观的差异。

1. 组件定义:从 .vue 到 JSX 组件

Vue 的单文件组件(SFC)拆分了 templatescriptstyle,而 React 组件直接在 JS/TS 文件中用函数返回 JSX。

Vue 组件(Vue 3 组合式 API)

<!-- Hello.vue -->
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <button @click="handleClick">点击</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const msg = ref('Hello Vue')
const handleClick = () => {
  msg.value = '点击后的文本'
}
</script>

<style scoped>
.hello { color: red; }
</style>

React 组件(函数组件)

// Hello.jsx
import { useState } from 'react';
import './Hello.css'; // 样式单独引入

const Hello = () => {
  // 状态定义(替代 Vue 的 ref)
  const [msg, setMsg] = useState('Hello React');

  // 事件处理(替代 @click)
  const handleClick = () => {
    setMsg('点击后的文本'); // 状态更新(React 需显式调用更新函数)
  };

  // JSX 直接返回(替代 template)
  return (
    <div className="hello"> {/* class → className(避免与 JS 关键字冲突) */}
      <h1>{msg}</h1> {/* 插值用 { } 替代 {{ }} */}
      <button onClick={handleClick}>点击</button> {/* @click → onClick(驼峰命名) */}
    </div>
  );
};

export default Hello;
2. JSX vs Vue Template:语法细节对比
功能Vue TemplateReact JSX
插值{{ message }}{ message }
条件渲染v-if="isShow" / v-else{ isShow ? <div>显示</div> : <div>隐藏</div> }{ isShow && <div>显示</div> }
列表渲染v-for="(item, index) in list" :key="index"list.map((item, index) => <div key={index}>{item}</div>)
事件绑定@click="handleClick" / @input="handleInput"onClick={handleClick} / onChange={handleInput}(驼峰命名)
属性绑定:src="imgUrl" / :class="{ active: isActive }"src={imgUrl} / className={isActive ? 'active' : ''}
样式绑定:style="{ color: textColor }"style={{ color: textColor }}(双层大括号:外层 JSX,内层对象)

三、核心特性对比:状态、生命周期、事件

1. 状态管理:从 ref/reactiveuseState/useReducer

Vue 用 ref/reactive 定义响应式状态,React 用 useState(简单状态)或 useReducer(复杂状态)。

场景Vue 3React
简单状态const count = ref(0); count.value++const [count, setCount] = useState(0); setCount(prev => prev + 1)
对象状态const user = reactive({ name: 'xx' }); user.name = 'yy'const [user, setUser] = useState({ name: 'xx' }); setUser(prev => ({ ...prev, name: 'yy' }))(需「不可变更新」)
复杂状态逻辑Pinia store(actions 处理逻辑)useReducer(类似 Vuex 的 reducer)或 Redux

关键区别
React 状态更新是「不可变的」(不能直接修改原状态,需返回新对象),而 Vue 可以直接修改响应式对象(内部通过 Proxy 追踪变化)。

2. 生命周期:从 mounteduseEffect

Vue 的生命周期钩子(如 mountedupdated)在 React 中统一用 useEffect 模拟,更灵活但需理解依赖逻辑。

Vue 生命周期React useEffect 实现
created + mounteduseEffect(() => { /* 组件挂载后执行 */ }, []);(空依赖数组 → 只执行一次)
updated(监听某个状态)useEffect(() => { /* 依赖变化时执行 */ }, [count]);(依赖数组含 countcount 变则执行)
beforeUnmountuseEffect(() => { return () => { /* 组件卸载前清理 */ }; }, []);(返回清理函数)

示例:监听窗口大小(Vue vs React)
Vue:

<script setup>
import { onMounted, onUnmounted } from 'vue';
let width = 0;
const handleResize = () => { width = window.innerWidth; };
onMounted(() => window.addEventListener('resize', handleResize));
onUnmounted(() => window.removeEventListener('resize', handleResize));
</script>

React:

import { useState, useEffect } from 'react';

const ResizeDemo = () => {
  const [width, setWidth] = useState(0);

  // 监听窗口大小(mounted 时绑定,unmounted 时解绑)
  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    // 清理函数(替代 beforeUnmount)
    return () => window.removeEventListener('resize', handleResize);
  }, []); // 空依赖 → 只执行一次

  return <div>窗口宽度:{width}</div>;
};
3. 事件处理:从 @clickonClick
  • 命名规则:Vue 用短横线(@click@input),React 用驼峰(onClickonChange)。
  • 事件对象:Vue 用 $event,React 直接接收事件对象(合成事件,兼容各浏览器)。
  • 传参方式:Vue 可直接在模板传参(@click="handleClick(id, $event)"),React 在函数中绑定(onClick={() => handleClick(id, e)})。

示例:带参数的点击事件
Vue:

<template>
  <button @click="handleClick(123, $event)">点击</button>
</template>
<script setup>
const handleClick = (id, e) => {
  console.log(id, e.target);
};
</script>

React:

const EventDemo = () => {
  const handleClick = (id, e) => {
    console.log(id, e.target);
  };
  return (
    <button onClick={(e) => handleClick(123, e)}>点击</button>
  );
};

四、进阶特性:路由、状态库、样式

1. 路由:vue-router vs react-router-dom
功能vue-router@4react-router-dom@6
路由配置createRouter + routes 数组createBrowserRouter + routes 数组
导航组件<router-link to="/home">首页</router-link><Link to="/home">首页</Link>
路由出口<router-view /><Outlet />
参数获取useRoute().params.iduseParams().id
编程式导航useRouter().push('/home')useNavigate()(('/home'))

示例:React 路由基本用法

// 路由配置(router.js)
import { createBrowserRouter } from 'react-router-dom';
import Home from './Home';
import User from './User';

const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  { path: '/user/:id', element: <User /> }, // 动态路由参数
]);

// 根组件(App.jsx)
import { RouterProvider } from 'react-router-dom';
import router from './router';

const App = () => <RouterProvider router={router} />;

// User 组件获取参数
import { useParams } from 'react-router-dom';
const User = () => {
  const { id } = useParams(); // 获取路由参数
  return <div>用户 ID:{id}</div>;
};
2. 状态管理:Pinia vs Redux Toolkit

Vue 常用 Pinia 管理全局状态,React 常用 Redux Toolkit(RTK),核心思想类似(集中式状态管理),但 API 不同。

功能PiniaRedux Toolkit
状态定义defineStore 定义 store,直接修改状态createSlice 定义 slice,通过 reducer 更新状态
异步逻辑actions 中直接写 async/awaitcreateAsyncThunk 定义异步 action
状态获取useStore() 直接获取useSelector 选择状态
状态更新store.count++store.increment()dispatch(increment())

示例:计数器状态管理
Pinia:

// store/counter.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++; }
  }
});

// 组件中使用
import { useCounterStore } from './store/counter';
const Counter = () => {
  const store = useCounterStore();
  return <button @click={store.increment}>{store.count}</button>;
};

Redux Toolkit:

// store/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
  name: 'counter',
  initialState: { count: 0 },
  reducers: {
    increment: (state) => { state.count++; } // RTK 内部支持直接修改(Immer 库)
  }
});
export const { increment } = counterSlice.actions;

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './counterSlice';
export const store = configureStore({ reducer: { counter: counterSlice.reducer } });

// 组件中使用
import { useSelector, useDispatch } from 'react-redux';
import { increment } from './store/counterSlice';
const Counter = () => {
  const count = useSelector(state => state.counter.count);
  const dispatch = useDispatch();
  return <button onClick={() => dispatch(increment())}>{count}</button>;
};
3. 样式处理:从 scoped 到 CSS-in-JS

Vue 用 scoped 样式隔离,React 无内置方案,常用以下方式:

  • CSS Modules:类似 scoped,通过文件名 xxx.module.css 实现隔离。
  • Styled Components:用 JS 写样式,支持动态样式。
  • Tailwind CSS:原子类样式(Vue/React 通用)。

示例:CSS Modules 用法

/* Button.module.css */
.button {
  color: white;
  background: blue;
}
.active {
  background: red;
}
import styles from './Button.module.css';
const Button = ({ isActive }) => (
  <button className={`${styles.button} ${isActive ? styles.active : ''}`}>
    按钮
  </button>
);

五、避坑指南:Vue 转 React 常见误区

  1. 状态更新异步性
    React 中 setState 是异步的,不能直接在更新后读取新值:

    // 错误:无法立即获取更新后的值
    const [count, setCount] = useState(0);
    const handleClick = () => {
      setCount(count + 1);
      console.log(count); // 仍为 0(旧值)
    };
    
    // 正确:用函数式更新或 useEffect 监听
    setCount(prev => prev + 1); // 函数式更新确保依赖最新值
    
  2. 双向绑定 vs 受控组件
    Vue 用 v-model 实现双向绑定,React 需手动实现「受控组件」:

    // 输入框受控组件(替代 v-model)
    const InputDemo = () => {
      const [value, setValue] = useState('');
      return (
        <input 
          value={value} // 绑定状态
          onChange={(e) => setValue(e.target.value)} // 监听变化更新状态
        />
      );
    };
    
  3. JSX 必须有根节点
    Vue 模板允许多个根节点,React JSX 必须有唯一根节点(或用 <> 空标签包裹):

    // 错误:多个根节点
    return (
      <div>1</div>
      <div>2</div>
    );
    
    // 正确:用空标签包裹
    return (
      <>
        <div>1</div>
        <div>2</div>
      </>
    );
    

六、学习路径:快速掌握 React

  1. 基础阶段

    • 掌握 JSX 语法和函数组件。
    • 吃透 useState(状态)和 useEffect(副作用)两个核心 Hooks。
    • 练习条件渲染、列表渲染、事件处理。
  2. 进阶阶段

    • 学习路由(react-router-dom)和状态管理(Redux Toolkit 或 Context + useReducer)。
    • 掌握其他常用 Hooks:useRef(DOM 引用)、useMemo(缓存计算)、useCallback(缓存函数)。
  3. 实战阶段

    • 用 React 重构你熟悉的 Vue 小项目(如 TodoList、后台表格)。
    • 学习生态工具:TypeScript 集成、Vite 构建、测试工具(Jest + React Testing Library)。

总结

Vue 和 React 本质是「用不同方式解决相同问题」,核心能力(组件化、状态驱动)相通。重点关注 JSX 语法、Hooks 逻辑(尤其是 useEffect)、单向数据流 这三个差异点,通过 1-2 个实战项目练习,就能快速上手 React。

如果遇到具体问题,对比两者的 API 文档(React 文档Vue 文档)是最好的方法!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐