第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:为不同浏览器写不同代码
var el = 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期已经很熟悉这种写法了
let todos = [
{ id: 1, text: '学 HTML', done: true },
{ id: 2, text: '学 CSS', done: false },
];
function renderTodos() {
const ul = 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('');
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
todo.done = !todo.done;
renderTodos(); // 每次都要手动重新渲染
}
function addTodo(text) {
todos.push({ id: Date.now(), text, done: false });
renderTodos(); // 手动同步 UI
}
renderTodos(); // 初始渲染
问题: 每次状态变化都要手动调用 renderTodos();随着逻辑复杂,你可能忘了在某个地方调用,UI 就不同步了。
写法二:jQuery
// jQuery 风格:链式操作 DOM,但问题本质一样
$(function() {
let todos = [];
function render() {
$('#todoList').empty();
todos.forEach(todo => {
const li = $('<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', () => {
const text = $('#input').val().trim();
if (text) {
todos.push({ id: Date.now(), text, done: false });
render(); // 手动 render
}
});
});
问题本质一样: jQuery 让 DOM 操作更方便了,但没有解决"状态 → UI 同步"的根本问题。
写法三:Vue 3
<template>
<div>
<input v-model="newTodo" @keyup.enter="addTodo" placeholder="新 Todo">
<button @click="addTodo">添加</button>
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done">
<span :class="{ done: todo.done }">{{ todo.text }}</span>
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
const newTodo = ref('');
const todos = ref([
{ id: 1, text: '学 HTML', done: true },
{ id: 2, text: '学 CSS', done: false },
]);
function addTodo() {
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 版本 >= 18
node --version
# 创建第一个 React 项目(下期用到)
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
npm run 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提交
更多推荐


所有评论(0)