1.1 React 简介


文档摘要

1.1 React 简介 本节摘要:React 是一个用于构建用户界面的 JavaScript 库,核心思想是组件化、声明式与单向数据流。本节先回答「React 解决了什么」——它把 UI 拆成独立可复用的组件,用声明式描述界面而非命令式操作 DOM;再带你写一个最小的 React 应用,跑通从组件到页面的完整链路。 学习目标 阅读完本节,你应当能够: 说出 React 的三大思想:组件化、声明式、单向数据流 解释虚拟 DOM 与真实 DOM 的关系 手写一个最小 React 应用,说明它的结构 对比函数组件与类组件的基本差异 一、问题与直觉:为什么前端需要 React 先抛一个问题:2009 年前后,前端是怎么写界面的? 那时候 jQuery 是主角。

1.1 React 简介

本节摘要:React 是一个用于构建用户界面的 JavaScript 库,核心思想是组件化、声明式与单向数据流。本节先回答「React 解决了什么」——它把 UI 拆成独立可复用的组件,用声明式描述界面而非命令式操作 DOM;再带你写一个最小的 React 应用,跑通从组件到页面的完整链路。

学习目标

阅读完本节,你应当能够:

  1. 说出 React 的三大思想:组件化、声明式、单向数据流
  2. 解释虚拟 DOM 与真实 DOM 的关系
  3. 手写一个最小 React 应用,说明它的结构
  4. 对比函数组件与类组件的基本差异

一、问题与直觉:为什么前端需要 React

先抛一个问题:2009 年前后,前端是怎么写界面的?

那时候 jQuery 是主角。你想让页面里一个数字跟着按钮点击变,得这样写:先找到这个元素,再改它的文本,再绑定事件。界面每变一次,你就得手动操作一次 DOM。页面小还好,页面一大,「找元素—改内容—绑事件」这套流程堆成山,代码越写越像一团揉皱的线。

React 换了个思路:别告诉我怎么改界面,告诉我界面应该长什么样。

这就是声明式。你描述「当计数为 5 时页面显示什么」,React 负责算出怎么从当前状态变成那个样子,并把差异最小化地应用到真实 DOM 上。开发者从「操作 DOM」的泥潭里解放出来,专注写业务逻辑。

SOURCE 原文给了一个关键结论:React 由 Facebook 开发并维护,被广泛用于构建单页应用(SPA)和移动应用。SPA 的特点是一整张页面由一个入口加载,之后的页面切换不再整页刷新——这正好依赖 React「数据变了,界面跟着变」的能力。

二、核心思想逐条拆解

组件化:界面是积木

React 应用由一个个独立、可复用的组件构成。每个组件负责渲染页面的一部分,并管理自己的状态。组件可以嵌套:一个页面组件由导航栏组件、内容区组件、底部组件拼起来,每个组件内部还能继续拆分。

组件化的直接收益是复用和可维护。同样的按钮写一次,全站复用;改样式只动一处。SOURCE 原文把组件定义为「React 应用的基本构建块」,这个定义值得记住——后面所有章节都在围绕怎么把组件写得更好。

声明式:描述而非指挥

命令式代码回答「怎么做」,声明式代码回答「是什么」。看一段对比就能体会:

// 命令式思路(伪代码):手动找元素、改内容 const counterEl = document.getElementById('counter'); counterEl.textContent = String(count); // 声明式思路:描述 UI 应该长什么样 function Counter({ count }) { return <p id="counter">{count}</p>; }

React 拿到组件返回的描述(JSX),自己决定怎么更新真实 DOM。开发者不再操心「先删掉旧节点还是先插入新节点」这种细节。

单向数据流:数据往一个方向走

数据从父组件流向子组件,子组件不能直接改父组件的状态。这个「只能往下流」的限制初看是束缚,实际是定心丸——状态变化有明确路径可循,出了问题能顺藤摸瓜找到源头。后面讲状态管理时,单向数据流是贯穿始终的原则。

虚拟 DOM:性能的底座

虚拟 DOM 是真实 DOM 的轻量级表示。当组件状态变化时,React 先在内存里更新虚拟 DOM,再对比新旧虚拟 DOM 找出差异,只把差异部分应用到真实 DOM。

为什么要多这一层?因为直接操作真实 DOM 代价高——浏览器每改一次布局就可能重排重绘。在内存里比较 JavaScript 对象又快又省,算出差量再一次性落地。

三、第一个 React 应用:动手跑起来

概念讲再多,不如敲一个。假设环境已装好(第 1.2 节详述),创建一个最小应用:

function App() { return ( <div className="App"> <h1>Hello, React!</h1> </div> ); } export default App;

这段代码的骨架值得逐行看:

代码片段 作用
function App() 定义一个名为 App 的函数组件
return ( ... ) 函数组件必须返回一个 JSX 元素,描述它的 UI
<div className="App"> JSX 元素,和 HTML 相似但 class 写成 className
export default App 导出组件,供其他文件引用

把 App 挂载到页面靠入口文件:创建 root 并调用 render,把组件渲染到指定的真实 DOM 节点上。SOURCE 原文里这个流程清晰标注了「import React → 定义组件 → 导出」,这就是 React 应用的最小结构。

函数组件与类组件:两条路

React 组件可以是函数,也可以是类。函数组件就是一个接收 props、返回 JSX 的纯函数:

function Greeting(props) { return <h1>Hello, {props.name}!</h1>; }

类组件是 ES6 类,继承自 React.Component,必须实现 render 方法:

import React from 'react'; class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } increment = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.increment}>Increment</button> </div> ); } }

两者的定位在 React 16.8 之后发生了变化:Hooks 让函数组件也能管理状态,官方推荐新代码用函数组件。但类组件的生命周期方法、this 绑定问题,仍然大量存在于存量项目里,读旧代码、维护老项目时你必须认识它。

props 与 state 的分工

这是最容易搞混的一对概念,一次讲清楚:

  • props:父组件传给子组件的数据,只读。子组件不能改自己的 props。它像函数的入参。
  • state:组件内部的数据,可变。state 变化会触发组件重新渲染。它像函数里的局部变量,但每次变化都带着界面更新。

看个例子。父组件把用户信息作为 props 传给子组件,子组件展示它:

function Profile(props) { return ( <div> <h2>{props.name}</h2> <p>Age: {props.age}</p> </div> ); } function App() { return <Profile name="John Doe" age={30} />; }

name="John Doe"age={30} 是父组件传给 Profile 的 props。注意 age 用了花括号——JSX 里凡是要传 JavaScript 值(数字、变量、表达式)都要包花括号,字符串字面量可以直接写。

state 的用法上面类组件 Counter 里已经见过:constructor 里初始化,setState 里修改。函数组件用 useState(第 2.2 节详解)。

💡 关键直觉:把组件想象成纯函数——同一次渲染里,props 和 state 决定了输出什么界面。data 变,渲染变;渲染变,用户看到的内容变。抓住这条因果链,后面所有内容都是它的展开。

四、React 从哪来:一段简短历史

React 的诞生和 Facebook 的痛点绑在一起。2011 年前后,Facebook 的广告系统 UI 复杂度爆炸,传统 DOM 操作式的开发已经撑不住——界面状态一多,手动同步 DOM 的代码量呈指数增长,bug 层出不穷。Facebook 工程师 Jordan Walke 带着团队做出了一个叫 FaxJS 的原型,核心思路就是「用函数描述 UI,数据变了自动更新」,后来这个思路演化成 React。

2013 年 React 开源,2015 年 React Native 发布,同一套声明式组件模型被带到了移动端——这也是 React 后来能横跨 Web 与 App 的起点。2016 年 Redux 出现,把单向数据流和不可变状态推到了极致,成为 React 生态事实上的标配一段时间。2017 年 React 16 引入 Fiber 架构重构了内部调度,让渲染可以被中断、被分片,为 Suspense 和并发渲染铺路。2019 年 React 16.8 正式发布 Hooks,函数组件从此能管理状态和副作用,React 的写法发生了根本变化。

这条时间线告诉我们一件事:React 的每次大版本都在解决「声明式 UI 在更大规模下如何保持高效」这个命题。理解了这一点,你就明白为什么虚拟 DOM 要做 Diff、为什么要有 key、为什么 Hooks 的依赖数组那么讲究——它们不是炫技,是同一个问题在不同阶段的解法。

四之二、React 生态的大致版图

经常有新手问:学 React 是不是还得学一堆别的?答案是:React 本身只管视图,但一个能上线的项目确实需要配套工具。大致分五类:

类别 常见选择 何时需要
脚手架 Create React App、Vite 建项目时
路由 React Router 多页面时
状态管理 Context、Zustand、Redux Toolkit 跨组件共享状态时
样式 CSS Modules、styled-components、Tailwind 写样式时
测试 Jest、React Testing Library 保证质量时

这份清单先混个眼熟即可。第 4 章会逐个展开,并给出选型依据——哪类项目用哪套组合,为什么要这样选,代价是什么。

五、为什么选择 React:横向看它的位置

SOURCE 原文列了几个选 React 的理由,我按实际分量重新排一下:

理由 说明 分量
组件化 代码可维护、可复用 核心优势,Vue 也有
声明式 专注于「界面长什么样」而非「怎么改 DOM」 与 Vue 相似,强于原生
生态庞大 组件库、状态库、脚手架选择极多 React 的护城河
跨平台 配 React Native 可写移动应用 独有优势之一
虚拟 DOM 减少真实 DOM 操作,提升性能 现在各家都有,已不稀奇

一个诚实的判断:单论「声明式 + 组件化」,React 和 Vue 是一类东西。React 真正的护城河是生态——前后端、工具链、招聘市场几乎被它占满。选 React 很少是纯技术决定,更多是「跟谁一起写、招什么人、生态够不够」的综合判断。

⚠️ 常见坑:以为 React 是框架。它是库——只管视图层,路由要自己接 React Router,状态管理要自己选 Redux 或 Zustand,脚手架要自己配 Vite 或 CRA。这既是自由也是责任,第 3、4 章专门处理这些选型问题。

关于声明式的一个容易误会的点

有人觉得「声明式 = 不用管 DOM 操作」,这句话只对了一半。React 只是替你管了,不代表你不用懂。你需要知道虚拟 DOM 是什么、Diff 怎么比、为什么 key 影响性能——因为声明式只是把操作藏进了框架,性能瓶颈依然会找上门。这也是为什么第 2 章第一节就讲虚拟 DOM 与 Diff:它不是选学内容,是理解 React 一切行为的钥匙。

还有一层理解:声明式并不是 React 独有。HTML 本身就是声明式的——你写一个列表标签描述列表,浏览器负责渲染。React 的贡献是把这种声明式能力推进到「数据变化时界面自动跟随」的层面。想明白这层对比,你就理解了 React 在技术史上做的事:它把「界面等于状态的函数」这个函数式思想从数学书搬进了浏览器。

一个真实场景:SPA 为什么非 React 不可

单页应用(SPA)的核心诉求是:切换页面不整页刷新。传统多页应用每次跳转都向服务器要一个全新的页面,白屏、闪烁、状态丢失都难以避免。SPA 只加载一次,之后的路由切换在前端完成——但前端怎么知道界面该变成什么?答案还是那句:界面是状态的函数。路由变了,状态变了,组件重新渲染,页面局部更新。

React Native 更进一步:同样的组件模型,编译成原生控件渲染,Web 与移动端共享大部分业务逻辑。SOURCE 原文特别强调 React 可与 React Native 结合构建跨平台应用,这个「一份心智、两处落地」的能力是不少团队押注 React 的原因。当然它不是免费的——跨平台带来的是抽象层的取舍,性能损耗和平台特性缺失总要还一点,这属于后话,本章先知道有这条路即可。

要点速记

  • 声明式思想:描述「界面应该是什么」,不指挥「怎么操作 DOM」
  • 单向数据流:数据从父流向子,子不能改父的状态
  • 虚拟 DOM:内存中轻量级表示,Diff 后最小化更新真实 DOM
  • 函数组件 vs 类组件:前者是纯函数,后者有 state 与生命周期,Hooks 之后官方推荐函数组件
  • props 只读、state 可变:props 是入参,state 是局部变量但变化触发重渲染
  • JSX 传值规则:传 JavaScript 值用花括号,字符串字面量可裸写

下一节我们搭建真正的开发环境——光会看代码不够,得让代码跑起来,先比较 CRA 和 Vite 两条路怎么选。环境跑通之后,你就有条件亲手验证本节讲的所有概念了。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U