news 2026/10/2 2:02:54

AI全栈实战 | 2.2-02 React 思维模型:数据不可变 vs Vue 数据可变,两种哲学把复杂度推给谁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI全栈实战 | 2.2-02 React 思维模型:数据不可变 vs Vue 数据可变,两种哲学把复杂度推给谁

上篇回顾:2.2-01 拆解了 Vue3 的 Proxy 响应式、组合式 API、组件通信、双向绑定本质。本篇讲 React——前端另一大框架。对后端工程师来说,React 的心智模型比 Vue 陡峭得多(JSX + Hooks + 不可变数据),但理解 React 能让你形成「为什么同样的需求两种框架设计完全不同」的判断力。

一、开篇:同一个需求,Vue 和 React 两种写法

需求:一个计数器,点击 +1,显示当前值。

Vue3:

<template> <button @click="count++">{{ count }}</button> </template> <script setup> import { ref } from 'vue'; const count = ref(0); </script>

React:

import { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>{count}</button>; }

表面看差不多,但底层哲学截然不同:

  • Vue:count++直接修改数据,响应式自动更新 UI
  • React:setCount(count + 1)创建新值触发重新渲染,不能直接修改 count

这就是本篇的核心命题:数据可变 vs 数据不可变,两种哲学各自把复杂度推给了谁。

二、JSX:HTML in JavaScript

2.1 JSX 是什么

JSX 不是 HTML,是 JavaScript 的语法扩展:

const element = <h1 className="title">Hello</h1>;

编译后变成:

constelement=React.createElement('h1',{className:'title'},'Hello');

所以 JSX 本质是createElement的语法糖。

2.2 与 Vue 模板的区别

维度Vue 模板JSX
语言HTML 扩展(v-if/v-for)JavaScript 表达式
灵活度受限(模板语法)完全灵活(JS 能力)
学习曲线低(像 HTML)中(要懂 JS)
类型检查弱强(TS 友好)

Vue 模板把逻辑限制在模板语法内,JSX 把模板融入 JS。各有优劣——Vue 对新手友好,JSX 对高级用户灵活。

三、虚拟 DOM 与 diff 策略

3.1 为什么需要虚拟 DOM

直接操作真实 DOM 很慢(重排重绘)。虚拟 DOM 是一棵 JS 对象树,修改时先改虚拟 DOM,再 diff 出最小变化,批量更新真实 DOM。

// 虚拟 DOM 节点{type:'div',props:{className:'box'},children:[{type:'span',props:{},children:['Hello']}]}

3.2 diff 算法的三个假设

  1. 不同类型节点 → 直接替换(div 变 span,整个子树重建)
  2. 同类型节点 → 复用 DOM,更新属性
  3. 列表 diff → 用 key 标识(key 相同复用,不同销毁重建)

3.3 key 的重要性

// 没 key:React 按位置 diff,可能错乱 items.map(item => <li>{item.text}</li>); // 有 key:React 按 key diff,精准匹配 items.map(item => <li key={item.id}>{item.text}</li>);

不要用 index 做 key——列表中间插入/删除时,index 变化导致 React 误判,性能差且可能 bug。

3.4 Vue 和 React 的虚拟 DOM 一样吗

底层思路一样(diff + 最小更新),但:

  • Vue2:全量 diff
  • Vue3:编译时标记静态节点,diff 时跳过(PatchFlag)
  • React:Fiber 架构,可中断 diff(时间分片)

四、Hooks:函数式组件的状态

4.1 React 的函数式理念

React 推崇函数式编程:组件是纯函数,输入 props 输出 UI。但纯函数没有状态——Hooks 就是给函数组件加状态的「钩子」。

function Counter() { const [count, setCount] = useState(0); // 状态钩子 return <button onClick={() => setCount(count + 1)}>{count}</button>; }

4.2 useState 的正确理解

const[count,setCount]=useState(0);
  • count:当前值(不可变!不能count++)
  • setCount:触发更新的函数
  • 0:初始值

setCount做两件事:

  1. 更新内部状态(创建新值,不修改旧的)
  2. 触发组件重新渲染

4.3 useEffect:副作用钩子

function UserList() { const [users, setUsers] = useState([]); useEffect(() => { fetch('/api/users') .then(res => res.json()) .then(data => setUsers(data)); }, []); // 空依赖数组:只在挂载时执行一次 return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>; }

useEffect的依赖数组:

  • 不传:每次渲染后都执行
  • []:只在挂载时执行
  • [dep1, dep2]:dep 变化时执行

4.4 依赖数组的陷阱

useEffect(() => { fetch(`/api/user/${userId}`) .then(setUser); }, [userId]);

如果忘了加userId到依赖数组,userId 变了但 effect 不重新执行——数据不更新。这是 React 最常见的 bug 之一。

ESLint 的react-hooks/exhaustive-deps规则会自动检测这个问题。

五、数据不可变:React 的核心原则

5.1 为什么不能直接修改

// 错误:直接修改 state const [list, setList] = useState([1, 2, 3]); list.push(4); setList(list); // React 不会重新渲染!

React 用Object.is比较新旧 state,引用相同就跳过渲染。list.push没改引用,React 认为没变。

// 正确:创建新数组 setList([...list, 4]); // 新引用,触发渲染

5.2 不可变数据的哲学

React 的核心理念:数据不可变(immutable)。每次修改都创建新值,旧值不变。

好处:

  1. 时间旅行(undo/redo):旧状态还在
  2. 性能优化:引用比较比深比较快
  3. 并发安全:不可变数据天然线程安全

代价:

  1. 内存开销:每次创建新对象
  2. 心智负担:要记住不能直接改

5.3 Vue 的可变哲学

conststate=reactive({list:[1,2,3]});state.list.push(4);// 直接修改,响应式触发

Vue 用 Proxy 拦截修改,知道你改了什么。不需要创建新对象。

5.4 两种哲学把复杂度推给谁

哲学复杂度推给优势
React 不可变开发者(要手动创建新值)性能优化简单(引用比较)
Vue 可变框架(Proxy 拦截要追踪所有修改)开发者心智负担小

结论:React 把数据管理的复杂度推给开发者,换性能优化的简单;Vue 把复杂度吞进框架,换开发体验的简洁。没有对错,看团队偏好。

六、受控组件 vs 非受控组件

6.1 受控组件

function Form() { const [text, setText] = useState(''); return <input value={text} onChange={e => setText(e.target.value)} />; }

输入框的值由 React state 控制。每次输入都触发 setState → 重新渲染。

6.2 非受控组件

function Form() { const inputRef = useRef(); return <input ref={inputRef} defaultValue="" />; }

输入框的值由 DOM 自己管,React 通过 ref 读取。

推荐:表单用受控组件(数据在 React 里,便于校验和提交);简单场景用非受控(性能好)。

七、Vue vs React 选型对比

维度Vue3React
心智模型可变数据 + 响应式不可变数据 + 重新渲染
模板模板语法JSX
状态ref/reactiveuseState/useReducer
副作用watch/watchEffectuseEffect
生态国内中后台强国际化、跨平台
TS 支持好(Vue3 重写)极好(JSX 天然适配)
学习曲线平缓陡峭
适合场景管理后台、中后台复杂交互、React Native

后端转前端推荐 Vue3,但理解 React 能让你明白「为什么有不同的设计选择」。

八、小结表

概念ReactVue 对照
视图描述JSX模板
状态useStateref/reactive
数据原则不可变可变
副作用useEffectwatchEffect
性能优化引用比较Proxy 追踪
列表 key必须必须
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 2:01:37

AI Agent支付背后的七套协议:从TLS到MCP全解析

AI Agent支付&#xff0c;从2024年底开始就成了支付圈最热的关键词。但真正立案子去接支付协议时我才发现&#xff1a;所谓AI支付&#xff0c;根本没有一套现成的"AI支付协议"&#xff0c;它是在过去四十年的支付技术地基上&#xff0c;一层一层堆出来的。翻了一遍家…

作者头像 李华
网站建设 2026/10/2 2:00:20

HowToCook 菜谱实战:韭菜炒蛋的做法与大火快炒技术要点解析

文档教程 【免费下载链接】HowToCook Programmers guide about how to cook at home. 项目地址&#xff1a; https://gitcode.com/GitHub_Trending/ho/HowToCook 点击查看 免费下载 韭菜炒蛋是一道经典家常快炒菜&#xff0c;本文以开源项目 HowToCook 仓库中的 韭菜炒蛋.md 菜…

作者头像 李华
网站建设 2026/10/2 1:59:30

VSCode + OpenGL 环境配置实战:从零跑通渲染管线

简介&#xff1a;这份资源面向希望用轻量编辑器入门图形编程的开发者&#xff0c;尤其是习惯VSCode、想避开Visual Studio重型配置的C学习者。它解决的是OpenGL环境搭建门槛高、库依赖繁琐的问题&#xff0c;通过一份可直接运行的工程模板&#xff0c;把GLFW、GLAD等第三方库与…

作者头像 李华
网站建设 2026/10/2 1:58:53

cpp-httplib 进阶功能速览:从 Streaming、SSE 到认证、压缩与中间件

后端网络 【免费下载链接】cpp-httplib A C header-only HTTP/HTTPS server and client library 项目地址&#xff1a; https://gitcode.com/GitHub_Trending/cp/cpp-httplib 点击查看 免费下载 恭喜你完成了 cpp-httplib Tour 全部章节的学习&#xff01;你已经掌握了 httpli…

作者头像 李华