从Vue3过渡到React

590 阅读6分钟

在当今前端生态中,Vue3和React作为两大主流框架,各有其独特的优势。本文将为Vue3开发者系统梳理过渡到React所需的关键思维转换和技术调整。我是前端小白,花了一星期简单的学习了一下react的基础知识,一直以来都用vue框架开发,先是要求用原生微信小程序写个小程序,现在要来学习react。

1.核心范式差异

Vue3采用"渐进式框架"设计,提供官方全家桶解决方案,强调"约定优于配置"。React则定位为"UI构建库",只处理视图层,其他功能依赖社区生态,奉行"组合优于继承"原则。

2.模版系统差异

Vue的单文件组件(SFC)将模板、逻辑和样式分离:

<template>
  <button @click="increment">{{ count }}</button>
</template>

React则采用JSX实现JavaScript与UI的混合表达:

<button onClick={increment}>{count}</button>

3.实践心得

刚接触到react时,就发现react启动服务npm start 比vue启动服务要慢好多,默认用的是webpack构建。而且还不同于vue的构建,没有配上任何路由和状态管理。后来发现react也可以用vite构建。

组件化开发的话,react和原生js像,react可以在js中写html,因为有jsx。区别于vue有专门的.vue写组件,react组件分为两类:一类是函数组件,一类是class组件,就跟vue3,vue2一样的版本。react老版本用的是class组件,新版本用的是函数组件,之前学过java、ts倒也能适应。

在事件绑定上,react类似原生,on + 方法名(首字母大写区分原生),还不能像vue一样直接调用这个方法,要给方法调用bind规定this或方法本身写成箭头函数,传递参数也要借助bind()方法。

在响应式数据上,react不能像vue一样直接修改 触发更新,react修改能改值,但无法触发更新,因为react没有像vue一样监听get和set,而是在调用setState的时候调用react的更新操作,用setState通过浅合并来修改数据,感觉跟原生微信小程序有点像。在双向绑定上,React 通过 手动绑定 valueonChange 实现双向绑定,需显式调用 setState 更新数据,习惯用vue的model绑定的我在这方面慢了。

到react中的样式操作css上,感觉好麻烦啊,一度学不下去了。在生命周期的执行上,vue是因为在get和set里触发更新,vue在get部分有一个重要的操作-依赖收集,在更改了数据之后,只会更新用到这个数据的地方,做到最小的更新范围,而react的更新是调用方法时触发的,并没有依赖收集的过程,所以它会更新整个组件树,比如修改父组件,会把子组件一起更新,即便是更新的数据和子组件没有任何关系,不过用PureComponent可以阻止。在ref上原理一个道理,在vue中创建方式是ref()函数,react是createRef()或useRef(),访问值vue是.value,react是.current。学到了高阶组件,第一次听说高阶组件,看学习视频上说类似于vue中的mixin,我去搜了一下已经被Vue3标记为不推荐使用,推荐使用Composition API来实现代码复用,高阶组件是复用操作逻辑,运算的,我在vue3用自定义指令(Directives)做了防抖点击指令功能,跟react的高阶指令还挺相似的。

在路由上,react在各自组件就能够实现路由功能,的确自由,vue3是将路由统一封装到router/index.js文件中,react用BroserRouter包裹要使用路由的根组件,使用Routes组件,定义具体路由显示区域,使用Route组件,定义具体路由规则,使用NavLink组件,定义调整链接,嵌套路由,vue3通过嵌套,react通过组件;动态路由都是通过 参数;编程式导航vue3用router.push/replace(),react使用useNavigate();懒加载vue3使用() => import 动态导入,react用lazy() + ;还有路由参数,react的params用useParams(),query用useSearchParams()(返回URLSearchParams对象,结构成一个数据和方法,跟useMemo的hook相似),loacation用useLocation(),vue3都是useRoute(),state传递,react是通过navigate的state选项,vue3是通过router.push的state选项;react的路由管理也可以像vue3一样写成列表渲染;

在状态管理上,React,没有专门的状态管理库,都是通用的js状态管理库,所以我们首先创建一个全局的数据储存和管理工具,通过其他工具,数据的修改能触发react页面的更新。

组件库的话,vue3我习惯用elementPlus ,react用Ant Design。

路由和状态管理在Vue3和React都很重要,用代码展示一下:

react基础用法:

import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { Suspense, lazy } from 'react'const Home = lazy(() => import('./views/Home'))
const About = lazy(() => import('./views/About'))
const User = lazy(() => import('./views/User'))
​
function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/user/:id" element={<User />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  )
}

嵌套路由:

<!-- 父路由组件 -->
<template>
  <div>
    <router-view></router-view> <!-- 子路由出口 -->
  </div>
</template><!-- 路由配置 -->
{
  path: '/parent',
  component: Parent,
  children: [
    { path: 'child', component: Child }
  ]
}
// 父路由组件
function Parent() {
  return (
    <div>
      <Outlet /> {/* 子路由出口 */}
    </div>
  )
}
​
// 路由配置
<Route path="parent" element={<Parent />}>
  <Route path="child" element={<Child />} />
</Route>

编程式导航传参:

import { useNavigate } from 'react-router-dom';
​
function Component() {
  const navigate = useNavigate();
  
  // 传递params
  navigate('/user/123');
  
  // 传递query
  navigate('/user?name=John');
  
  // 传递state
  navigate('/user', { state: { from: 'home' } });
}
import { useRouter } from 'vue-router';
​
const router = useRouter();
​
// 传递params
router.push('/user/123');
​
// 传递query
router.push({ path: '/user', query: { name: 'John' } });
​
// 传递state
router.push({ path: '/user', state: { from: 'home' } });

响应式参数变化:

// 需要手动监听变化
import { useEffect } from 'react';
import { useParams } from 'react-router-dom';
​
function User() {
  const { id } = useParams();
  
  useEffect(() => {
    // 当id变化时执行
  }, [id]);
}
<script setup>
import { watch } from 'vue';
import { useRoute } from 'vue-router';
​
const route = useRoute();
​
// 自动响应式
watch(() => route.params.id, (newId) => {
  // id变化时自动触发
});
</script>

全局状态:

// store.js
import { createStore } from 'redux'function counterReducer(state = { value: 0 }, action) {
  switch (action.type) {
    case 'increment':
      return { value: state.value + 1 }
    default:
      return state
  }
}
​
const store = createStore(counterReducer)
​
// 组件中使用
import { useSelector, useDispatch } from 'react-redux'function Counter() {
  const count = useSelector(state => state.value)
  const dispatch = useDispatch()
​
  return (
    <button onClick={() => dispatch({ type: 'increment' })}>
      {count}
    </button>
  )
}
// stores/counter.ts
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  getters: {
    doubleCount: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++
    },
    async fetchData() {
      // 异步操作
    }
  }
})
​
​
<script setup>
import { useCounterStore } from '@/stores/counter'const counter = useCounterStore()
</script>
​
<template>
  <div>{{ counter.count }}</div>
  <div>{{ counter.doubleCount }}</div>
  <button @click="counter.increment()">+</button>
</template>

4.总结

vue3:使用模板语法(.vue单文件组件),通过v-bindv-on等指令绑定数据与事件,更接近 HTML 语法,直观易读。React:采用 JSX 语法,将 HTML 与 JavaScript 融合,以 JavaScript 表达式嵌入 UI 逻辑,更强调代码的动态性与灵活性。建议深入学习 React 的核心概念,如 hooks、JSX、单向数据流,理解其与 Vue3 的本质区别。可能是刚学react的知识,感觉还是Vue3我用着好使,有好多已经封装好的直接用,不过react在某些方面的确灵活,都说大项目用react好,来学习一下。