盖房子有两种盖法:一种是从头到尾现场砌砖,把门、窗、墙统统浇铸成一体,改一扇门恨不得拆半面墙;另一种是在工厂里把墙体、门窗做成标准模块,运到工地像拼乐高一样组合起来——谁都能参与,改一处不影响全局,这就是前端世界的「组件化」。React 正是这套“预制模块”体系的代表:组件是模块,Props 是模块间的接口,JSX 是施工图纸,Babel 是把图纸翻译成施工指令的翻译官。这篇教程就用「建造智能房子」这个比喻,带你从零看懂 React 组件化设计与 JSX 语法的精髓,搞懂它,再学 Vue、Angular 也能触类旁通。

岗位关联

学会用组件化眼光拆解界面、设计 Props 接口、看懂 JSX 编译原理,是前端工程师从“能写页面”进阶到“能设计系统”的必修课。

目录
  1. 可视化演示
  2. 组件化思想
  3. 组件拆分
  4. Props设计
  5. 高内聚低耦合
  6. JSX语法
  7. Babel编译
  8. 渲染流程
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示组件拆分原则、JSX编译原理、Props通信与HOC复用模式。

本节配有交互动效(进入视口后自动加载,约 3KB)。

组件化拆分原则 将复杂界面拆分为独立可复用的UI构建单元 每个组件管理自身状态实现高内聚低耦合 App = Component₁ + Component₂ + ... + Componentₙ 组件组合构建复杂应用如同乐高积木拼接

组件化思想

盖房子有两种盖法:一种是从头到尾现场砌砖,把门、窗、墙统统浇铸成一体,改一扇门恨不得拆半面墙;另一种是先在工厂里把墙体、门窗做成标准模块,运到工地像拼乐高一样组合。React 的组件化显然是后者——组件就是工厂预制的标准模块,它可以是一个按钮、一张卡片,也可以是一整个页面,所有界面都由组件一个套一个地拼装起来,这张“爆炸图”就叫组件树。

在 React 里,组件本质上是返回 JSX 的函数或类:函数组件用 function App() { return <div/>; } 声明,类组件用 class App extends React.Component 声明。无论哪种,组件名必须大写字母开头,这是 React 识别“这是组件而不是普通 HTML 标签”的约定。组件化带来的三个直接好处是复用性——同一模块用在多个页面;可维护性——修改只发生在局部;可测试性——每个模块都能独立验证。

一个典型页面可以抽象成根组件 App 内部嵌套几个子组件,用公式表达就是组件树的组合关系:

把界面看成“预制模块的组合”,后续的拆分、接口设计、编译原理都围绕这一思想展开——这就是 React 组件化的世界观。

UI=App(Header+Sidebar+Main+Footer)\mathrm{UI} = \mathrm{App}(\mathrm{Header} + \mathrm{Sidebar} + \mathrm{Main} + \mathrm{Footer})
  1. 根组件 AppApp 作为整栋房子的总装配图,负责把各区域组织起来。
    App(⋅)\mathrm{App}(\cdot)
  2. 加号表示组合这里不是算术加法,而是“嵌套与组合”——Header、Sidebar 等子组件作为模块被装进 App。
    Header+Sidebar+Main+Footer\mathrm{Header} + \mathrm{Sidebar} + \mathrm{Main} + \mathrm{Footer}
  3. 大写字母约定组件名首字母必须大写,这样 JSX 才能区分“这是组件标签”还是“这是 HTML 标签”。
    App, Header, Sidebar\mathrm{App},\ \mathrm{Header},\ \mathrm{Sidebar}

组件拆分

工厂造门时,会把门拆成门框、门板、合页,每件单独生产、质量可控;但要是拆到一颗螺丝钉,反而浪费资源。组件拆分同样要找准粒度。衡量粒度最常用的尺子是单一职责原则:让每个组件只负责一件明确的事,其他事交给别的组件。

“怎么分组件”没有一个绝对标准,但有一套成熟的分析套路:先画页面草图,划分有独立语义的区块——头部、侧栏、内容区;再对内部仍有复杂度的区块继续细分,形成“原子-分子-页面”的层级结构,这就是原子化拆分。经典的分工法是把组件分成两类:容器组件负责拿数据和业务逻辑,展示组件只负责按 Props 渲染界面,这叫容器与展示分离。

用集合论的眼光看,拆分后的每个组件都对应一块互不重叠的职责区域:

门框、门板、合页各司其职,整栋房子才能顺畅组装——组件拆分不是“拆得越碎越好”,而是“每块都有清晰的唯一职责”。

Ci:Ri,Ri∩Rj=∅ (i≠j)C_i : R_i, \quad R_i \cap R_j = \varnothing \ (i \neq j)
  1. 组件与职责的映射$C_i$ 表示第 $i$ 个组件,冒号表示它负责职责 $R_i$。
    Ci:RiC_i : R_i
  2. 职责不重叠$R_i \cap R_j = \varnothing$ 表示任意两个组件的职责边界没有交集,一件事只有一个负责人。
    Ri∩Rj=∅R_i \cap R_j = \varnothing
  3. 下标约束$i \neq j$ 限定这是两个不同组件之间的比较。
    i≠ji \neq j

Props设计

模块之间怎么“通电通水”?工地靠的是标准插座和水管接口——规格一确定,任何工厂生产的模块都能插上。React 里这个接口就是 Props。Props 是父组件传给子组件的“使用说明加原料包”:父组件在子组件标签上写属性,子组件通过 props 参数读取。比如 <Header title="首页" /> 就是把 title 传给了 Header。

Props 最重要的性格是只读——子组件只能看不能改,数据流永远是从上到下的单向数据流。想改数据?调用父组件通过 Props 传下来的回调函数,让父组件改自己的 state。此外,设计一套好 Props 等于设计一套好接口:尽量传“必要的数据”而非“整个页面”;用 defaultProps 给参数定默认值,让组件缺参数时也有兜底;用 propTypes 或 TypeScript 声明参数类型,在开发阶段就能发现调用错误。

把组件看作一个函数,Props 就是它的入参集合,同一个组件传入不同 Props 就渲染出不同结果:

接口规格越稳定,模块组合越自由。好组件会把 Props 当作对外承诺的“合同”——只读、有默认值、有类型约束,用起来才踏实。

Component(p)=g(props),props 只读\mathrm{Component}(p) = g(\mathrm{props}), \quad \mathrm{props}\ \text{只读}
  1. 组件是函数$\mathrm{Component}(p)$ 表示组件接收来自父级的参数 $p$。
    Component(p)\mathrm{Component}(p)
  2. 输出由 Props 决定$g(\mathrm{props})$ 表示渲染结果是 Props 的某种映射,Props 变则界面变。
    g(props)g(\mathrm{props})
  3. 只读约束$\mathrm{props}$ 只读,这是单向数据流的根基,保证数据变化可追踪。
    props 只读\mathrm{props}\ \text{只读}

高内聚低耦合

厨房模块内部水管、电路、烟道安排得满满当当,关上厨房门,你在客厅完全感知不到它内部怎么运转——这叫高内聚;厨房和客厅只通过一扇门和一个插座相连,拆掉厨房不至于搞垮客厅——这叫低耦合。高内聚低耦合是软件设计的老话,也是组件设计绕不开的标尺。

高内聚指组件内部的东西彼此紧密相关、共同完成一件事;低耦合指组件之间的依赖尽量少、尽量薄。一个把按钮样式和登录逻辑全写在一起的组件,内聚低;一个在渲染时直接操作父组件状态的组件,耦合高。实操技巧有三条:把状态和行为放进最贴近它的组件里;对外只暴露最少量的 Props,业务通过回调交给父组件处理,而不是让子组件去偷改别家状态;组件内部的常量和工具函数就近组织,不散落到全局。

组件设计的质量可以浓缩成一句话:内聚度上升,耦合度下降:

厨房自成一体、对外简简单单,房子才能灵活改造。组件的可维护性,本质上就是高内聚与低耦合之间的平衡艺术。

Cohesion↑, Coupling↓\mathrm{Cohesion} \uparrow,\ \mathrm{Coupling} \downarrow
  1. 内聚度上升$\mathrm{Cohesion}$ 表示组件的内部聚合程度,箭头朝上代表内部联系越来越紧密。
    Cohesion↑\mathrm{Cohesion} \uparrow
  2. 耦合度下降$\mathrm{Coupling}$ 表示组件之间的依赖程度,箭头朝下代表模块间联系越来越少。
    Coupling↓\mathrm{Coupling} \downarrow
  3. 两者同步优化逗号连接两个趋势,说明优秀设计是让这两个指标同时朝理想方向变化。
    Cohesion↑, Coupling↓\mathrm{Cohesion} \uparrow,\ \mathrm{Coupling} \downarrow

JSX语法

施工图纸有一套简洁符号:一个方框加一条线,工人就知道“这里装门”。JSX 就是 React 的图纸语言——用类似 HTML 的标签结构,把“屏幕上长什么样”直接写出来。JSX 全称是 JavaScript XML,它是 JavaScript 的语法扩展:允许在 JS 里直接写类 XML 的标签,但浏览器不认 JSX,它只是开发期的“图纸”。

图纸上可以标注三类信息。第一是标签结构:用 <div>、<Header> 这样的标签描述元素与组件嵌套关系。第二是表达式插值:用花括号 {} 嵌入任何 JavaScript 表达式,比如 {user.uppercase()},计算结果会渲染到界面。第三是逻辑渲染:条件渲染用三目运算符 {isLogin ? <User/> : <Login/>};列表渲染用 array.map(item => <li key={item.id}>{item.name}</li>),这里的 key 是 React 对比列表时的身份证。

JSX 的优雅在于它是一种声明式描述——你只写“这里是什么”,不用写“怎么把它画出来”:

图纸上一段简洁标注,翻译出来是完整施工指令;JSX 也如此,写的是一眼就懂的 UI 结构,真正的执行逻辑留给后面的编译环节。

标签结构+{JS表达式}→界面描述\text{标签结构} + \{\text{JS表达式}\} \rightarrow \text{界面描述}
  1. 标签结构JSX 用尖括号标签描述界面骨架,如 <div>、<Header>,对应图纸上的方框线。
    标签结构\text{标签结构}
  2. 表达式插值花括号内放 JavaScript 表达式,运行时会把计算结果填入界面,对应图纸上的标注文字。
    {JS表达式}\{\text{JS表达式}\}
  3. 产出界面描述箭头右侧表示 JSX 整体描述的是“界面该长成什么样”,具体绘制交给 React。
    →界面描述\rightarrow \text{界面描述}

Babel编译

图纸符号工人看不懂怎么办?需要翻译官把图形语言逐句译成施工指令。Babel 就是 JSX 的翻译官。JSX 之所以能用在工程里,全靠 Babel 在构建阶段完成翻译,整个过程分三步:解析(Parse)把源码变成 AST 抽象语法树,转换(Transform)把 JSX 节点替换成函数调用,生成(Generate)输出标准 JavaScript。

翻译的产物就是 React.createElement。它是 React 创建元素的底层 API,type 表示组件类型或标签名,props 承载属性,children 是子节点。JSX 里写一行 <App name="x" />,等价于调用一次 React.createElement(App, { name: "x" }),它返回的 React 元素是普通 JavaScript 对象,描述“屏幕上该有什么”——也就是虚拟 DOM 里的一个节点。

把编译过程写成一条流水线,最核心的转换就是 JSX 到 createElement 的映射:

没有翻译官,图纸就是天书;没有 Babel,JSX 就是废纸。理解这一层,你才算真正读懂“JSX 是语法糖”这句话。

JSX→Babel编译React.createElement(type, props, ...children)\mathrm{JSX} \xrightarrow[\text{Babel}]{\text{编译}} \mathrm{React.createElement}(\mathrm{type},\ \mathrm{props},\ ...\mathrm{children})
  1. 编译箭头$\xrightarrow{\text{Babel}}$ 表示转换发生在 Babel 编译阶段,不是浏览器运行时。
    →Babel编译\xrightarrow[\text{Babel}]{\text{编译}}
  2. 第一个参数 type$\mathrm{type}$ 表示组件类型或 HTML 标签名,决定创建什么元素。
    type\mathrm{type}
  3. 第二个参数 props$\mathrm{props}$ 是属性对象,承载 JSX 上写的所有标签属性。
    props\mathrm{props}
  4. 剩余参数 children$...\mathrm{children}$ 表示子节点列表,对应标签内部嵌套的内容。
    ...children...\mathrm{children}

渲染流程

图纸和模块都齐了,施工队按什么顺序干活?先搭结构柱、再装墙体、最后布置内装。React 的渲染也分阶段。组件从出生到消失要经历三个阶段:挂载(Mount)——组件第一次被放入页面;更新(Update)——props 或 state 变化导致重新渲染;卸载(Unmount)——组件从页面消失。类组件里对应 componentDidMount、componentDidUpdate、componentWillUnmount 三个生命周期钩子(新版 React 推荐函数组件 + Hooks 的 useEffect 统一处理)。

每次渲染,React 执行组件的 render 逻辑产出虚拟 DOM(React 元素树),与上次的虚拟 DOM 做对比,找出差异(diff),再精准更新真实 DOM。这就是声明式 UI 的含义:你只描述结果,React 负责“怎么改”。理解挂载/更新/卸载,能帮你定位“请求放哪发”“定时器在哪清理”这些经典问题。

一次完整的首次渲染可以表达为:

施工顺序清晰,房子才能如期落成;渲染阶段想明白,组件的一生你心里就有数了。

Mount:props+state→VirtualDOM→RealDOM\mathrm{Mount}: \mathrm{props} + \mathrm{state} \rightarrow \mathrm{Virtual DOM} \rightarrow \mathrm{Real DOM}
  1. 挂载起点$\mathrm{Mount}$ 表示组件第一次插入页面,props 和 state 是它的初始输入。
    Mount\mathrm{Mount}
  2. 输入原料$\mathrm{props} + \mathrm{state}$ 代表组件渲染所需的全部数据来源。
    props+state\mathrm{props} + \mathrm{state}
  3. 虚拟 DOM 中转$\rightarrow \mathrm{Virtual DOM}$ 表示先产出描述界面的虚拟节点树。
    →VirtualDOM\rightarrow \mathrm{Virtual DOM}
  4. 真实 DOM 落地$\rightarrow \mathrm{Real DOM}$ 表示 React 对比差异后更新真实页面。
    →RealDOM\rightarrow \mathrm{Real DOM}

AI 应用场景

企业中后台组件库建设

阶段:组件抽象与复用治理

解决的问题:传统方式下每个后台页面都从零写表格、弹窗、表单,同样的交互逻辑散落几十个文件,改一个交互要全局搜索替换。用组件化思想把高频界面抽象成统一组件(如 ProTable、ProForm),通过 Props 配置差异,就能一处维护、处处复用。

具体案例:某金融公司搭建内部门户,把筛选表单、分页表格、详情抽屉封装成 20 个基础组件,业务方只需传 Props 描述“要哪些列、哪个接口”,开发周期从两周缩短到三天。

多团队并行开发大型应用

阶段:团队协作与接口契约管理

解决的问题:一个大型页面由一个团队串行开发时,前后端、前端内部互相阻塞。按组件拆分后,各小组像装修队一样各装各的模块,只要 Props 接口提前约定好,就能并行施工、最后拼装联调。

具体案例:电商首页拆成 Header、商品瀑布流、购物车浮层三个组件,A 组负责数据逻辑、B 组负责视觉呈现,通过约定的 items、onAddToCart 等 Props 完成对接,版本迭代互不踩踏。

从 JSX 思维迁移到跨端框架

阶段:模板编译与跨端适配

解决的问题:小程序、uni-app、Vue 模板都有自己的“类 JSX”语法,初学者常常被不同模板语法困住。理解了 Babel 编译 JSX 的原理后,你会明白所有模板语言本质上都是“描述界面 + 编译成可执行代码”,语法差异只是表面,底层思想完全相同。

具体案例:一个习惯 React 的开发者接手 Taro 小程序项目,发现 WXML 里也能用表达式插值和列表渲染,直接把组件化拆分经验复制过去,三天内就完成首屏迁移。

Python 演示

python59 行
class Component:    """模拟 React 组件基类"""    def __init__(self, props=None):        self.props = props or {}     def render(self):        raise NotImplementedError  class Header(Component):    def render(self):        title = self.props.get("title", "默认标题")        return "<header>" + title + "</header>"  class Sidebar(Component):    def render(self):        items = self.props.get("items", [])        lis = "".join("<li>" + item + "</li>" for item in items)        return "<aside><ul>" + lis + "</ul></aside>"  class Main(Component):    def render(self):        text = self.props.get("text", "")        return "<main>" + text + "</main>"  class Footer(Component):    def render(self):        info = self.props.get("info", "")        return "<footer>" + info + "</footer>"  class App(Component):    """组合子组件, 模拟组件化布局"""    def render(self):        header = Header({"title": self.props.get("title")})        sidebar = Sidebar({"items": self.props.get("items")})        main = Main({"text": self.props.get("content")})        footer = Footer({"info": self.props.get("footer")})        return (            "<div>"            + header.render()            + sidebar.render()            + main.render()            + footer.render()            + "</div>"        )  if __name__ == "__main__":    page = App({        "title": "React 组件化",        "items": ["首页", "组件", "文档"],        "content": "JSX 最终编译为 JavaScript",        "footer": "(c) 2024 AI 讲师",    })    print(page.render())
目的:用 Python 模拟 React 组件化渲染器——每个子类都是一个组件,父组件通过 Props 向下传数据,最终拼接出完整页面结构。
  1. class Component:定义组件基类,相当于所有“预制模块”的公共底座。
  2. self.props = props or {}保存传入的 Props,没有传参时用空字典兜底。
  3. raise NotImplementedError强制子类实现 render 方法,保证每个组件都有“生产图纸”。
  4. default父组件通过 Props 把 title 传给子组件,体现从上到下的单向数据流。
  5. items = self.props.get("items", [])读取 Props 里的列表数据,没有就用空列表。
  6. "".join(...)列表渲染:把每个 item 逐个拼成 <li> 标签,对应 JSX 的 map 渲染。
  7. Header({...})父组件组装子组件,并把所需数据作为 Props 传入。
  8. page = App({...})创建根组件实例,传入整棵组件树的初始数据。
  9. print(page.render())触发整棵组件树渲染,输出完整 HTML 结构。

常见误区

误区初学者以为 JSX 就是 HTML,直接在里面写 `class="nav"`,结果样式不生效还报错,最后只能靠猜把 `class` 改成 `className`。

正解JSX 是 JavaScript 的语法扩展,不是 HTML。属性名走 JavaScript 的驼峰命名:class 要写 className,for 要写 htmlFor;而且 JSX 能嵌 {} 表达式,这是 HTML 做不到的。把它当“长得像 HTML 的 JavaScript”就对了。

为何常见:JSX 标签和 HTML 长得太像,浏览器里渲染出来的结果也像 HTML,初学者自然容易混淆二者的身份。

误区听说组件化要拆分,就把每个按钮、每行文字都单独拆成一个组件,拆到页面上几十个碎片组件,改一处逻辑要翻七八个文件。

正解拆分的目的是单一职责与复用。一个组件只有被两处以上复用、或者内部逻辑复杂到影响理解时才值得拆。无脑细拆只会降低可维护性——就像把门拆到一堆螺丝钉,装回去比装门还费劲。

为何常见:把“拆分”本身当成了目的,忽略了拆分背后的真实诉求是“边界清晰、易于维护”。

误区子组件拿到 `props.user.name`,觉得反正是个对象,直接 `props.user.name = 'new'` 改掉,再把值渲染到界面上。

正解Props 是只读的,这是单向数据流的根基。想改数据?调用父组件通过 Props 传下来的回调函数,让父组件改自己的 state;或者把数据提升为子组件自己的 state。直接改 Props 会导致数据流混乱,React 严格模式下也会给出警告。

为何常见:对象是引用类型,直接改属性通常“看起来生效了”,于是容易误以为 Props 可以随意修改。

误区有人觉得类组件才有生命周期、才有状态,函数组件只能接收 Props 画个静态 UI,低人一等。

正解React 16.8 引入 Hooks 后,函数组件用 useState、useEffect 就能获得状态和副作用能力,代码更简洁、逻辑更容易复用。现在 React 官方推荐优先写函数组件。类组件不是不能用,但“函数组件低级”的刻板印象已经过时。

为何常见:React 早期版本函数组件确实只能当“静态展示组件”,看多了旧资料就留下了旧印象。

误区以为 `React.createElement` 只是把 JSX 标签拼成 HTML 字符串,再塞进页面的 `innerHTML`。

正解createElement 返回的是普通 JavaScript 对象——React 元素,它是虚拟 DOM 的节点。React 用它做 diff 对比后,才通过 ReactDOM 把变更提交到真实 DOM。直接拼 HTML 字符串等于每次都整体重建页面,性能差且有 XSS 风险。

为何常见:看浏览器最终渲染出 HTML,容易倒推“是不是拼字符串拼出来的”,忽略了中间还有虚拟 DOM 这一层。

面试题

Q1. 关于 JSX 语法的描述,下列哪一项是正确的?

单选题 · easy

  • A.JSX 就是 HTML 可以直接被浏览器解析
  • B.JSX 是 JavaScript 的语法扩展和语法糖← 正确答案
  • C.JSX 只能用于小程序开发的模板编写
  • D.JSX 是 CSS 样式表的一种新的书写规范

答案:B。JSX 看起来像 HTML,但本质是 JavaScript 的语法扩展,浏览器不能直接识别,需要 Babel 编译。就像施工图纸不是房子本身,JSX 也不是页面本身,而是描述页面的语言。A 错在“直接解析”,C、D 说的应用范围完全不对。

Q2. 下列哪一项不是 React 组件化带来的核心好处?

单选题 · mid

  • A.组件可以在不同页面间实现复用
  • B.复杂界面可以按模块拆分协作开发
  • C.浏览器可以直接识别 JSX 无需编译← 正确答案
  • D.修改界面局部时不易牵连其他部分

答案:C。组件化的好处是复用、可维护、可并行开发,但“浏览器直接识别 JSX”是不可能的——JSX 必须经 Babel 编译。就像预制模块虽然好用,但工厂交货前必须经过标准工序,跳过编译这一步是不存在的。

Q3. 关于 React 中 Props 的说法,下列哪些选项是正确的?

多选题 · mid

  • A.Props 的数据流向是从父组件流向子组件← 正确答案
  • B.Props 在子组件内部是只读不可修改的← 正确答案
  • C.Props 可以通过 defaultProps 设置默认值← 正确答案
  • D.Props 只能传递数字和字符串类型的数据

答案:ABC。Props 是父传子的单向数据流,子组件不能直接修改,可以通过 defaultProps 设默认值、通过 propTypes 做类型校验。Props 可以传任意类型——对象、数组、函数都可以,所以 D 错。就像标准插座既能给手机充电也能给台灯供电,Props 的类型远不止两种。

Q4. 下列哪种做法最能体现组件拆分的单一职责原则?

单选题 · mid

  • A.把页面上所有功能逻辑塞进一个大组件
  • B.让每个组件只专注完成一项明确的职责← 正确答案
  • C.把每个组件拆成无意义的碎片化小文件
  • D.禁止拆分组件让所有代码保持内联实现

答案:B。单一职责原则是“一件事只有一个负责人”,B 正是这个意思。A 是典型的“大泥球”,C 是过度拆分,D 是另一个极端。就像门模块内部的门锁、把手各有分工,但不会把一颗螺丝钉单独当组件。

Q5. 以下哪些做法符合高内聚低耦合的组件设计思路?

多选题 · hard

  • A.组件内部实现细节对外完全隐藏不暴露← 正确答案
  • B.组件通过少量明确 Props 与外界通信← 正确答案
  • C.组件直接修改兄弟组件的内部状态数据
  • D.把相互关联的逻辑集中在组件内部实现← 正确答案

答案:ABD。高内聚指相关逻辑集中在一起(D),低耦合指对外暴露尽量少(A、B)。C 直接修改兄弟组件状态是典型的高耦合行为,会让数据流变得混乱。就像厨房内部管线路由齐全(高内聚),但和客厅只靠一个插座连接(低耦合),而不是把水管接到卧室去。

Q6. Babel 会把 JSX 中的 <App name="a" /> 编译成下列哪一项?

单选题 · mid

  • A.调用 createElement 创建 React 元素对象← 正确答案
  • B.直接修改浏览器中的真实 DOM 节点树结构
  • C.将 JSX 字符串原样插入到页面指定位置
  • D.生成 HTML 标签字符串并绕过 React 框架

答案:A。Babel 编译 JSX 的产物是 React.createElement(App, { name: "a" }) 调用,返回 React 元素(虚拟 DOM 节点),而不是直接操作真实 DOM。就像翻译官把图纸符号翻译成施工指令,而不是翻译官自己上手砌墙。

Q7. React 组件触发更新阶段(Update)最常见的原因是什么?

单选题 · hard

  • A.组件的 props 或 state 发生了变化← 正确答案
  • B.页面发生了浏览器窗口被关闭事件
  • C.组件所在的页面被彻底卸载清除
  • D.开发者重新修改了 JSX 源码文件

答案:A。更新阶段由 props 或 state 变化触发,React 重新执行渲染并 diff 后更新真实 DOM。卸载是独立阶段,浏览器关闭与 JSX 源码修改不会直接触发组件更新。就像房子重新装修是因为内部布局需求变了(props 变化),而不是因为房子本身要拆掉。

Q8. 关于 JSX 表达式插值,下列哪些说法是正确的?

多选题 · mid

  • A.可以用花括号嵌入任意 JavaScript 表达式← 正确答案
  • B.条件渲染可以通过三目运算符来实现← 正确答案
  • C.列表渲染通常配合 map 方法进行遍历← 正确答案
  • D.花括号内可以写完整的 for 循环语句

答案:ABC。花括号内只能放“表达式”而不能放语句,for 循环是语句,不能直接写进 {}。A、B、C 都是 JSX 的高频用法。就像图纸上的标注只能写简洁的规格说明,不能写一整段施工流程。

Q9. 下列哪一项是 React 函数组件的基本形态?

单选题 · easy

  • A.一个接收 props 并返回 JSX 的纯函数← 正确答案
  • B.一个返回 HTML 字符串的普通函数模板
  • C.一个只有样式没有业务逻辑的配置对象
  • D.一个直接修改 DOM 节点的构造器函数

答案:A。函数组件是“接收 props、返回 JSX”的纯函数,它不直接操作 DOM。返回 HTML 字符串是服务端模板的做法,配置对象不叫组件。就像一块预制墙板是“按规格生产、运到工地拼装”的模块,而不是一堆散装建材。

Q10. 关于 React 元素与真实 DOM 的关系,下列哪一项是正确的?

单选题 · extreme

  • A.React 元素是描述 UI 的普通 JavaScript 对象← 正确答案
  • B.React 元素就是浏览器中真实存在的 DOM 对象
  • C.React 元素必须被全局搜索才能定位到对应节点
  • D.React 元素等同于 HTML 字符串模板的渲染结果

答案:A。createElement 返回的 React 元素是普通对象,它描述“界面该是什么样”,经过虚拟 DOM diff 后才映射到真实 DOM。它不是真实 DOM、不是模板字符串,也不需要“全局搜索”这种操作。就像施工图纸是房子的描述,不是房子本身,也不是施工队。