浅谈感受之 React 与 Vue 😒

写在前面

本文不深入探讨 React 与 Vue 的源码或具体架构实现,而是站在一位同时使用过 Vue 和 React 的应用开发者视角,去感受和理解主流前端框架在设计上的各种思想与创意。凡是能被接纳并普及的东西,都有其存在的道理,本文只讲述主观感受,不涉及站队或评判某个框架的优劣~~

前端开发框架初体验

其实,目前几乎所有类似 React 或 Vue 的前端框架,核心都在解决前端开发中的两大问题:

1. 组件复用

一个应用的多个页面通常需要统一风格,因此按钮、开关等通用组件往往需要被多次复用。框架通过组件化机制,让这些 UI 单元可以被方便地拆分、封装和复用。

2. 视图与数据的关系

在大多数应用中,用户既可以通过视图操作影响数据,也可以通过改变数据来更新视图。写过传统原生三件套(HTML + CSS + JS)的开发者对此深有体会:每一次交互都需要手动修改变量或操作 DOM。当项目逐渐复杂庞大时,这些散落各处的 DOM 操作和维护逻辑会迅速失控,变得难以维护。

框架正是通过响应式数据绑定、声明式视图等机制,把"数据驱动视图"变成默认范式,从而显著降低这种维护成本。

当然目前很多框架能解决的问题不止这两个,还包括了很多其他特性,例如虚拟 DOM 映射、事件统一管理等等

React

React 是 facebook 团队出品的一款前端开发框架,但它其实更像一个库?它本身只负责 UI 渲染,路由、状态管理等由你自由选型,所以官方更倾向于叫它"用于构建用户界面的库",但实际使用上通常都会和其他很多库绑定使用,所以这个库和框架的界限比较模糊

React 的视图构建特性

React 将 UI 构造成组件树。每个组件可以维护自己的内部状态(state),并通过 props 接收父组件传来的数据(这些数据可能来自父组件的 state)。组件对外暴露 props 接口、对内封装状态与逻辑,因此成为可组合、可复用的独立部件。数据自上而下流动,状态应放在真正需要它的最近公共祖先中

React 的视图搭建采用 JSX/TSX------一种可嵌入 JavaScript 表达式的类 HTML 语法扩展,经编译转为 React 元素。它没有专用模板指令,列表渲染用 map()、条件渲染用 &&/三元表达式,全部是原生 JS 表达式,因此组合视图时灵活简便。但 {} 内只能放表达式而非语句,且 JSX 是声明式描述"给定数据下视图应呈现什么",实际 DOM 更新由 React 渲染机制完成,开发者并不直接命令式地操控视图

jsx 复制代码
const products = [
  { title: 'Cabbage', isFruit: false, id: 1 },
  { title: 'Garlic', isFruit: false, id: 2 },
  { title: 'Apple', isFruit: true, id: 3 },
];

export default function ShoppingList() {
  const listItems = products.map(product =>
    <li
      key={product.id}
      style={{
        color: product.isFruit ? 'magenta' : 'darkgreen'
      }}
    >
      {product.title}
    </li>
  );

  return (
    <ul>{listItems}</ul>
  );
}

React 的状态设计

React 的状态更新是声明式的:调用 setState 只是向 React 发起一次更新请求,不会立即改变当前代码中的变量值,也不会由开发者直接控制渲染时机。React 会将请求排队、合并(自动批处理),在调度后重新渲染;若新旧值相等还可能跳过更新。开发者能明确看到并决定的是更新逻辑与状态归属 ,而执行时机由 React 掌控。当前代码中读到的始终是本次渲染的快照值

jsx 复制代码
function MyButton() {  
    const [count, setCount] = useState(0);  
    function handleClick() {  
        setCount(count + 1);  
    }
    return (<button onClick={handleClick}>Clicked {count} times</button>);  
}

React 处理视图与数据关系的策略是手动通知式 :调用 setXXX 向 React 发起渲染请求,不调用则框架不会响应。Flutter 的 setState 采用了同样的契约

并且 React 还有一个重要的不可变特性,这个特性核心规则是:永远不要直接修改 state 或 props,而是创建一个新的副本,把新副本交给 React 。这不是 JavaScript 语言层面的强制约束,而是 React 运行时依赖的契约。直接修改(mutation)会导致一个致命问题:React 感知不到变化

如果你对数组调用 push,或直接给对象属性赋值,引用地址没有变。React 用 Object.is 比较新旧 state,发现引用相同,就会跳过重新渲染。界面不会更新,同时你还在无意中篡改了上一次渲染的"快照",导致调试时历史日志被污染。更深层的原因在于 React 的设计选择:它不劫持对象属性、不依赖 Proxy 追踪变化,因此你可以在 state 里放任意大的对象而无需额外性能开销

实际使用中通常结合 Immer 库一起使用,Immer 库赋予了在 React 中用"直接修改"的写法,自动得到不可变新状态 的能力(主要针对嵌套层数较深的对象,对这种对象做拷贝是比较麻烦的),它本质是 Proxy ,会记录你对它做的所有"修改"操作。回调结束后,Immer 根据这些记录,生成一个全新的不可变对象,原对象完全不受影响。所以代码看起来像在"违反规则"直接改,但底层产出的是符合 React 要求的新引用

js 复制代码
import { useImmer } from 'use-immer';

const [person, updatePerson] = useImmer({ name: 'A', artwork: { city: 'Paris' } });

updatePerson(draft => {
  draft.artwork.city = 'Lagos';  // 看起来在直接改,实际不是
});

感受

用 React 开发时,一个突出感受是它很贴合普通 JS/TS 的写法:组件都是函数,直接返回视图;状态更新和记忆类 Hook 也以函数调用的形式使用。整体手感接近原生 JS/TS 开发,侵入性较低。对从 Node.js 后端转来的开发者来说,通常会感到比较亲切。

不过,亲切的主要是语法形态和组合方式。真正的差异在运行时契约:组件函数会被反复执行,局部变量不会跨渲染保留,因此需要 Hook 来保存状态;组件体必须保持纯净,副作用要隔离到 useEffect 或事件处理函数中;Hooks 还有调用顺序的约束。

换句话说,React 让 UI 逻辑"长得像普通函数",但要求你按"UI 是状态的纯函数、渲染可重复执行"来思考,跨过这一层认知后,后端经验反而会成为加分项

Vue

按官网文档的说法:Vue(发音 /vjuː/,类似 view)是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,提供了一套声明式、组件化的编程模型,帮助开发者高效地开发用户界面。Vue 同样是一款声明式前端框架,但其整体设计思想建立在响应式之上

Vue 的视图构建特性

Vue 同样将 UI 构造成组件树。每个组件可以维护自己的内部状态(ref、reactive),并通过 props 接收父组件传来的数据(这些数据可能来自父组件的状态)。组件对外暴露 props 接口、对内封装状态与逻辑,因此成为可组合、可复用的独立部件。数据同样自上而下流动,状态应放在真正需要它的最近公共祖先中

Vue 对组件的抽象与视图构建,可以概括为:以单文件组件(SFC)为封装单元,以模板声明视图结构,最终编译为渲染函数,产出虚拟 DOM 并由响应式系统驱动更新。它与 React 最大的不同在于,Vue 同时掌控编译器和运行时,在编译阶段做更多的静态优化,而非纯运行时的全量比对

vue 复制代码
<script setup> 
import { ref } from 'vue' 
const count = ref(0) 
</script> 

<template> 
<button @click="count++">Count is: {{ count }}</button> 
</template> 

<style scoped> 
button { font-weight: bold; } 
</style>

Vue 的响应式

"响应式"这个词在 Vue 语境下,核心意思是:数据变了,依赖这份数据的地方会自动跟着更新,不需要手动去通知

类似 Excel 表格中你在 A1 填 10,B1 写公式 =A1*2,B1 显示 20。当你把 A1 改成 20,B1 自动变成 40,你不需要去操作 B1

Vue 3 用 Proxy 代理你的状态对象。当你写 state.count 读取属性时,Proxy 的 get 拦截器被触发,Vue 此时记录:"当前正在执行的副作用(比如组件的 render 函数、一个 computed、一个 watchEffect)读取了 count。" 当你写 state.count = 1 赋值时,Proxy 的 set 拦截器触发,Vue 查出"哪些副作用依赖了 count",然后把它们重新执行一遍

所以响应式的两个支柱是:

  1. 依赖收集:读数据时,记下"谁在读"
  2. 触发更新:写数据时,通知"读过它的人"重新执行

感受

用 Vue 开发时,一个突出感受是它很贴近传统前端开发的直觉:视图写在 <template> 里,结构和 HTML 一脉相承;逻辑写在 <script> 里,状态用 ref / reactive 声明,改数据即可,界面自动跟着变。整体手感接近"增强版的 HTML + JS",有点像在编写"配置",对从 jQuery 或原生前端转来的开发者来说,通常会感到比较亲切

不过,亲切的主要是写法形态和语法外观。真正的差异在运行时机制:模板不是浏览器直接解析的 HTML,而是先被编译成 render 函数,再产出虚拟 DOM 并挂载;状态不是普通变量,而是被 Proxy 包裹的可观察对象,读写会触发依赖收集与更新通知;computed、watch、生命周期钩子也都有各自的执行时机和依赖追踪规则。

换句话说,Vue 让视图"长得像 HTML",但要求你按"数据是响应式源、模板是它的函数映射、更新由依赖自动驱动"来思考。跨过这一层认知后,传统前端的结构直觉反而会成为加分项

相关推荐
代码猎人1 小时前
前端怎么掌握模块化
前端
天才熊猫君1 小时前
前端队列,我是怎么从 `push + shift` 换成游标的
前端·javascript
星_离1 小时前
《Ajax - 实战基础篇》
前端·ajax
gCode Teacher 格码致知1 小时前
前端教学8:提高 CSS 选择器的优先级,有哪些方法?
前端·css·html5
u0111026752 小时前
Canvas 导出 PNG 时 quality 参数为什么不起作用
前端·javascript·vue.js
众链网络2 小时前
年卡跨淡旺季的有效期模型:不可用日期、次数与顺延规则
java·前端·数据库
2601_949847752 小时前
jose 跨端三方库仓颉适配全流程
前端·javascript·flutter
CappuccinoRose2 小时前
滚动交互体系
前端·javascript·交互·html5·1024程序员节
时空节拍AI数字人2 小时前
博物馆数字人讲解系统设计:知识库 schema、展项联动协议与时序控制
java·服务器·前端·人工智能·ai·语音识别