第11期 | 为什么需要框架?从jQuery到React
第11期 | 为什么需要框架?从jQuery到React
系列:AI前端工程师·从零基础到拿到Offer
模块二开篇。欢迎来到前端工程化的世界。
🎯 今天你将学会
- 理解前端框架演进的历史动力:每代框架解决了什么问题
- 用同一个功能(Todo列表)对比原生JS/jQuery/Vue/React四种写法
- 理解 React 的核心思想:声明式 UI 和组件化
- 建立框架选型的判断力:什么项目用什么框架
📖 核心知识
一、历史背景:前端从"美化页面"到"构建应用"
2000年代:服务端渲染时代
那时候根本没有"前端工程师"这个职位——前端是后端顺带干的。HTML 由服务器拼好整页返回,浏览器只负责展示。JavaScript 只用来做一点点动画和验证。
2006年:jQuery 的出现
jQuery 解决了一个当时巨大的痛点:浏览器兼容性。那时候同一段代码在 IE、Firefox、Safari 里行为不一样,jQuery 封装了这些差异,提供统一的 API:
// 不用 jQuery:为不同浏览器写不同代码varel=document.getElementById?document.getElementById('box'):document.all['box'];// 用 jQuery:一行搞定$('#box').hide().fadeIn(300);jQuery 统治前端长达10年。但随着 Web 应用越来越复杂,jQuery 的问题开始暴露:大量手动 DOM 操作,状态难以管理。
2013年:React 的出现
Facebook 的工程师遇到了这个问题:他们的页面状态极其复杂(通知数量、消息列表、好友状态……),任何一处更新都可能影响多个 UI 组件,用 jQuery 手动同步这些状态简直是噩梦。
React 的核心思想解决了这个问题:不手动操作 DOM,告诉框架"我希望 UI 是什么样子",框架负责更新 DOM。
二、用同一个 Todo 列表对比四种写法
我们来实现同样的功能:显示 todo 列表,可以添加新 todo,可以标记完成。
写法一:原生 JavaScript(命令式)
// 我们在第04-06期已经很熟悉这种写法了lettodos=[{id:1,text:'学 HTML',done:true},{id:2,text:'学 CSS',done:false},];functionrenderTodos(){constul=document.getElementById('todoList');ul.innerHTML=todos.map(todo=>`<li> <input type="checkbox"${todo.done?'checked':''}onchange="toggleTodo(${todo.id})"> <span style="${todo.done?'text-decoration:line-through':''}">${todo.text}</span> </li>`).join('');}functiontoggleTodo(id){consttodo=todos.find(t=>t.id===id);todo.done=!todo.done;renderTodos();// 每次都要手动重新渲染}functionaddTodo(text){todos.push({id:Date.now(),text,done:false});renderTodos();// 手动同步 UI}renderTodos();// 初始渲染问题:每次状态变化都要手动调用renderTodos();随着逻辑复杂,你可能忘了在某个地方调用,UI 就不同步了。
写法二:jQuery
// jQuery 风格:链式操作 DOM,但问题本质一样$(function(){lettodos=[];functionrender(){$('#todoList').empty();todos.forEach(todo=>{constli=$('<li>').appendTo('#todoList');$('<input type="checkbox">').prop('checked',todo.done).on('change',()=>{todo.done=!todo.done;render();// 还是手动 render}).appendTo(li);$('<span>').text(todo.text).css('text-decoration',todo.done?'line-through':'').appendTo(li);});}$('#addBtn').on('click',()=>{consttext=$('#input').val().trim();if(text){todos.push({id:Date.now(),text,done:false});render();// 手动 render}});});问题本质一样:jQuery 让 DOM 操作更方便了,但没有解决"状态 → UI 同步"的根本问题。
写法三:Vue 3
<template><div><inputv-model="newTodo"@keyup.enter="addTodo"placeholder="新 Todo"><button@click="addTodo">添加</button><ul><liv-for="todo in todos":key="todo.id"><inputtype="checkbox"v-model="todo.done"><span:class="{ done: todo.done }">{{ todo.text }}</span></li></ul></div></template><scriptsetup>import{ref}from'vue';constnewTodo=ref('');consttodos=ref([{id:1,text:'学 HTML',done:true},{id:2,text:'学 CSS',done:false},]);functionaddTodo(){if(newTodo.value.trim()){todos.value.push({id:Date.now(),text:newTodo.value,done:false});newTodo.value='';}}</script>变化:没有任何手动 DOM 操作!你只需要修改todos这个数据,Vue 自动更新 UI。
写法四:React
import { useState } from 'react'; function TodoApp() { const [todos, setTodos] = useState([ { id: 1, text: '学 HTML', done: true }, { id: 2, text: '学 CSS', done: false }, ]); const [input, setInput] = useState(''); const addTodo = () => { if (!input.trim()) return; setTodos([...todos, { id: Date.now(), text: input, done: false }]); setInput(''); }; const toggleTodo = (id) => { setTodos(todos.map(t => t.id === id ? { ...t, done: !t.done } : t)); }; return ( <div> <input value={input} onChange={e => setInput(e.target.value)} onKeyUp={e => e.key === 'Enter' && addTodo()} placeholder="新 Todo" /> <button onClick={addTodo}>添加</button> <ul> {todos.map(todo => ( <li key={todo.id}> <input type="checkbox" checked={todo.done} onChange={() => toggleTodo(todo.id)} /> <span style={{ textDecoration: todo.done ? 'line-through' : 'none' }}> {todo.text} </span> </li> ))} </ul> </div> ); }关键区别:没有任何document.querySelector,没有手动render(),没有innerHTML。你只是在描述"当 todos 是这个值时,UI 长什么样"——React 负责一切 DOM 操作。
三、React 的三个核心思想
1. 声明式(Declarative)
命令式(jQuery/原生JS):怎么做——"找到这个元素,改变它的文本,添加这个类" 声明式(React):要什么——"当 count 是 5 时,显示'5个任务'"声明式更符合人类思维,bug 更少,代码更可预测。
2. 组件化(Component-Based)
一个复杂页面可以拆成很多独立的、可复用的组件:
// 每个组件像一个自定义 HTML 标签 function App() { return ( <div> <Navbar /> {/* 导航栏组件 */} <HeroSection /> {/* 主图区域组件 */} <ArticleGrid articles={data} /> {/* 文章列表组件,接收数据 */} <Footer /> {/* 页脚组件 */} </div> ); }组件可以复用:Navbar在每个页面都用,改一处全部生效。
3. 单向数据流(One-Way Data Flow)
数据只从父组件流向子组件,不能反向。子组件想改数据,需要调用父组件传来的函数:
function Parent() { const [count, setCount] = useState(0); // 把数据和修改数据的函数都传给子组件 return <Child count={count} onIncrement={() => setCount(count + 1)} />; } function Child({ count, onIncrement }) { return ( <div> <p>计数:{count}</p> <button onClick={onIncrement}>+1</button> {/* 子组件不能直接改 count,只能调用 onIncrement */} </div> ); }单向数据流让数据变化可追踪,bug 更容易定位。
四、Virtual DOM:React 高效更新的秘密
React 不直接操作真实 DOM(操作 DOM 代价很高),而是先在内存里维护一个"Virtual DOM"(虚拟 DOM),每次状态变化后:
- 重新计算 Virtual DOM
- 对比新旧 Virtual DOM(Diffing 算法)
- 只把真正变化的部分同步到真实 DOM
这叫Reconciliation(协调)。
状态变化 → 重新渲染组件 → 得到新 Virtual DOM → Diff → 最小化 DOM 更新理解 Virtual DOM 对面试很重要,但在日常开发中你不需要关心它——React 自动处理。
五、框架选型指南
| 场景 | 推荐 | 理由 |
|---|---|---|
| 独立前端工程师求职 | React | 市场需求最大,生态最丰富 |
| 国内中小厂 | Vue 3 | 学习曲线低,文档完善 |
| 全栈/服务端渲染 | Next.js(React)或 Nuxt(Vue) | 内置 SSR/SSG |
| 超轻量页面(无需组件化) | 原生 JS | 不引入框架负担 |
| 可交互内容展示 | Svelte | 编译时优化,包体积小 |
| Angular 遗留项目 | Angular | 不要随便换框架 |
本课程选择 React 的原因:
- 国内外大厂普遍使用,面试需求最高
- 生态最丰富(Next.js、React Native、各类 UI 库)
- 掌握 React 后,Vue 上手很快(反之亦然)
- AI 应用开发(Vercel AI SDK、LangChain.js)基本都有 React 版本
六、React 生态全景
在深入学 React 之前,先知道它的生态:
React 核心 ├── 状态管理 │ ├── useState / useReducer(内置) │ ├── Context API(内置,跨组件传递) │ ├── Zustand(轻量,推荐) │ └── Redux Toolkit(复杂应用) │ ├── 路由 │ └── React Router(第12-20期会用到) │ ├── 服务端渲染框架 │ └── Next.js(全栈 React 应用首选) │ ├── UI 组件库 │ ├── shadcn/ui(现代,Tailwind CSS) │ ├── MUI(Material Design) │ └── Ant Design(国内常用) │ ├── 数据请求 │ ├── TanStack Query(服务端状态管理) │ └── SWR(Vercel 出品) │ └── 构建工具 └── Vite(现代打包工具,第17期专讲)你不需要全部学,按需取用。接下来几期我们先学核心。
🤖 AI协作实战
场景:让 AI 对比 React 和 Vue 的代码写法
我给 AI 的 Prompt:
请用 React 和 Vue 3 分别实现一个相同的功能: 一个带输入框的搜索过滤列表(输入关键词,实时过滤列表项)。 然后帮我对比: 1. 代码量和可读性 2. 状态管理方式的差异 3. 事件绑定语法的差异 4. 各自的学习曲线 不需要完整项目,只需要核心逻辑代码。AI 的分析摘要(我整理的):
| 对比维度 | React | Vue 3 |
|---|---|---|
| 状态声明 | const [val, setVal] = useState('') | const val = ref('') |
| 绑定值 | value={val} onChange={e => setVal(e.target.value)} | v-model="val" |
| 计算值 | const filtered = items.filter(...)直接写 | const filtered = computed(...) |
| 模板语法 | JSX(JS 中写 HTML) | 独立.vue文件(template/script/style) |
| 学习曲线 | 需要理解 JSX、hooks 思维 | 模板语法更接近 HTML,入门更友好 |
两者都很好用,我选 React 是因为市场需求和 AI 应用生态更大。
💻 动手练习
练习1(简单):不用框架,纯原生 JS 实现:当todos数组变化时(添加/删除/切换),观察你需要手动调用多少次render()。感受一下这种"手动同步"的繁琐。
练习2(阅读理解):把本期第二节的四种 Todo 写法全部读一遍,对照着找到:
- 每种写法里"添加 todo"的操作在哪里
- "标记完成"触发了什么
- "UI 更新"是如何发生的
练习3(准备工作):下期我们开始写 React,提前安装好环境:
# 确认 Node.js 版本 >= 18node--version# 创建第一个 React 项目(下期用到)npmcreate vite@latest my-react-app ----templatereactcdmy-react-appnpminstallnpmrun dev# 打开 http://localhost:5173,看到 React 欢迎页就成功了📌 本期要点
- 框架的本质:解决"状态变化时 UI 自动同步"的问题,而不是让 DOM 操作更方便
- React 三原则:声明式(描述要什么)+ 组件化(可复用单元)+ 单向数据流(数据可追踪)
- Virtual DOM:React 在内存里算好最小更新,再同步到真实 DOM,提高性能
- React vs Vue:两者思路相似,React 市场需求更大,Vue 入门更友好;掌握一个,另一个触类旁通
- 不要纠结选哪个:现在学 React,后面如果需要 Vue 一周就能上手
🔗 下期预告
第12期:React核心·JSX与组件
终于要写 React 了!下期从最基础的 JSX 语法开始,理解函数组件、Props、State,写出你第一个真正的 React 组件。
AI协作点:我们会让 AI 生成一批组件模板,然后拆解每一部分的意思——这是理解 React 最高效的方式之一。
如果你没有苹果电脑,需要上传ios到APPStore可以访问以下网站
iPA上传工具 - IPA解析与AppStore提交
