从零开始学前端 | 第二十七章:JSX 与组件基础
本章定位上一章我们已经先把 React 的认知地基打好了。你已经知道React 是一个用于构建用户界面的 JavaScript 库。React 很适合解决复杂界面的组织、复用和维护问题。React 很重要的两层思维是组件化、数据驱动界面。但如果只停留在“知道 React 的价值”你还没有真正进入 React 编码阶段。从这一章开始我们要正式迈出第一步开始读懂并写出最基础的 React 代码。这一章的核心任务有三个理解 JSX 到底是什么。掌握函数组件最基础的写法。建立页面拆分与组件组合的第一层思维。你会发现React 代码里最常见的“看起来像 HTML 的内容”其实并不是普通 HTML 文件而是 JSX。而 React 页面最基础的组织方式也不是把所有内容都堆在一个文件里而是把页面拆成多个有职责边界的组件再把它们组合起来。所以你可以把这一章理解成从“理解 React 为什么重要”走到“真正开始用 React 描述界面”。本章学习目标学完这一章后你应该能做到知道 JSX 是什么以及它和普通 HTML 的关系。理解 JSX 为什么看起来像 HTML但本质上是 JavaScript 语法扩展。掌握 JSX 最常见的几条基础语法规则。学会在 JSX 中渲染变量和简单表达式。学会用函数的方式编写最基础的 React 组件。知道组件名为什么通常要大写。理解页面如何由多个组件组合而成。掌握组件拆分与组合的基本判断标准。为下一章学习Props与组件复用做好准备。一、从“React 是什么”到“真正开始写 React”上一章我们一直在回答“为什么要学 React”。这一章开始我们就要慢慢进入React 代码到底长什么样。很多人第一次打开 React 文件最先感受到的通常是代码里怎么会出现像 HTML 一样的标签这些标签为什么写在 JavaScript 或 TypeScript 文件里为什么一个组件看起来像一个函数页面为什么会由很多名字首字母大写的标签拼起来这些问题背后分别对应着 React 入门最关键的两个概念JSX组件你只要把这两个概念先建立起来后面的props、state、列表渲染、事件处理、状态更新学习起来都会顺得多。二、JSX 到底是什么先给一个当前阶段最够用的理解JSX 是一种写在 JavaScript 或 TypeScript 文件里的“界面描述语法”。很多资料会告诉你JSX 是JavaScript XML的缩写。这个名字你知道就行但当前阶段更重要的不是背全称而是理解它在做什么。1. 先看一个最简单的 JSX 例子const pageTitle h1欢迎进入 React 世界/h1;如果你第一次看到这行代码最容易冒出的想法通常是这不就是 HTML 吗看起来确实很像。但它不是普通 HTML 文件里的标签而是写在 JavaScript 或 TypeScript 代码里的 JSX。2. JSX 最核心的作用是什么它的核心作用是让你可以用一种更接近“页面长相”的方式去描述界面结构。如果没有 JSX你当然也能写 React。但写法会更绕也更不直观。所以对于初学者来说JSX 的价值非常大因为它把“界面结构”写得更像你已经熟悉的页面样子。3. 当前阶段先把 JSX 理解成什么就够了你现在可以先把 JSX 理解成一句非常实用的话JSX 看起来像 HTML但本质上是 JavaScript 里的语法扩展用来描述界面。只要这一句立住了后面很多看起来“奇怪”的写法就会顺很多。三、为什么 React 需要 JSX你可能会好奇明明已经有 HTML 了为什么 React 还要搞一个 JSX这是个很好的问题。React 引入 JSX并不是为了显得新奇而是因为在组件化开发里它真的很实用。1. 界面本身就很适合用“树形结构”来表达比如一个页面有一个头部有一个主内容区主内容区里有一个搜索栏还有一个列表列表里有很多卡片这种结构天然就很像标签嵌套的样子。而 JSX 恰好非常适合表达这种页面由多个嵌套层级组成的结构。2. React 里的界面和数据、逻辑关系很紧在原生开发里我们常常会把HTML 放在一个文件CSS 放在一个文件JavaScript 放在一个文件这没有问题。但在 React 里一个组件通常会同时关心这块界面长什么样里面要显示什么数据某些交互要触发什么逻辑JSX 的好处就在于它能让“界面结构”和“数据表达”靠得更近。3. JSX 会让组件阅读体验更自然先看一个非常简单的对比。如果只从“界面可读性”角度出发下面这种写法function WelcomeCard() { return ( section h2欢迎学习 React/h2 p这一章我们先理解 JSX 和组件基础。/p /section ); }对初学者来说通常比一层层函数调用的写法更容易看懂。所以当前阶段你不需要钻 JSX 的底层转换细节。你先把它看成React 为了更自然地描述界面结构而提供的一种写法。四、JSX 和普通 HTML 有什么关系这一节非常重要。因为很多初学者真正卡住的地方不是“不认识标签”而是以为 JSX 就等于 HTML。更准确的理解应该是JSX 借用了很多 HTML 的外观但它不是浏览器直接读取的 HTML 文件。1. 为什么它看起来那么像 HTML因为它们都在表达一件事页面结构。例如div h1标题/h1 p介绍文字/p /div这种层级关系本来就和 HTML 很接近。2. 但 JSX 比 HTML 更接近 JavaScript因为你会在 JSX 里看到这些东西花括号{}用来放变量和表达式组件标签如WelcomeCard /属性名使用className事件名通常写成onClick这类驼峰形式这些都说明JSX 虽然长得像 HTML但它工作在 JavaScript 的语境里。3. 当前阶段最重要的判断标准如果你分不清某段代码到底该怎么理解可以先问自己一句话这段内容是在 HTML 文件里还是在 React 组件函数里如果是在 React 组件函数里那它就应该按 JSX 的规则去理解。五、JSX 的几个最基础语法特点这一节你一定要慢慢看。因为后面几乎所有 React 代码都会不停地用到这些规则。六、第一条规则组件通常返回一个根元素看下面这段代码function App() { return ( main h1从零开始学前端/h1 p欢迎进入 React 阶段。/p /main ); }这里的main就是最外层的根元素。对于初学阶段来说你可以先记住一个组件返回界面时通常需要有一个最外层包裹结构。1. 为什么会有这个要求因为一个组件本质上要返回一块完整的界面结构。你可以先把它理解成返回结果需要有一个明确的整体。2. 不想多包一层怎么办React 里还可以使用片段写法function App() { return ( h1从零开始学前端/h1 p欢迎进入 React 阶段。/p / ); }这个写法你先认识就够了。当前阶段如果你不太熟先老老实实用一个最外层标签包起来也完全没问题。七、第二条规则标签要正确闭合在 HTML 里你可能已经见过一些浏览器能“帮你脑补”的写法。但在 JSX 里建议你一开始就养成更规范的习惯标签要写完整单标签也要自闭合。例如function ProfileCard() { return ( section h2学习档案/h2 img src/avatar.png alt头像 / /section ); }这里的img /就是自闭合标签。你可以先记住这个非常实用的规则成对标签要写开始和结束。单标签要写成自闭合形式。八、第三条规则属性写法和 HTML 不完全一样这是 React 初学者很容易踩坑的地方。因为你眼睛看到的像 HTML但它的很多细节其实更贴近 JavaScript。1.class在 JSX 里通常写成className例如function App() { return div classNamepage-containerReact 页面/div; }2. 事件名通常写成驼峰形式例如function ActionButton() { return button onClick{() console.log(点击了按钮)}点击我/button; }当前阶段你先认识onClick这种写法就够了后面讲事件时会展开。3.for相关场景常写成htmlFor例如function SearchInput() { return ( div label htmlForkeyword搜索关键词/label input idkeyword / /div ); }这类差异你一开始不用死记硬背太多。更稳的方式是先记住一句话JSX 属性不是机械照搬 HTML而是要按 React 的规则来写。九、第四条规则用花括号{}放变量和表达式这一条非常关键。你可以把它理解成当你要在 JSX 里放 JavaScript 内容时通常就会用到花括号。先看一个最简单的例子function WelcomeCard() { const userName 小白; return h2你好{userName}/h2; }这里的userName就是一个普通变量。因为它出现在 JSX 标签内容里所以需要用{}包起来。1. 花括号里能放什么当前阶段你可以先理解成变量字符串拼接结果数学表达式三元表达式调用函数后的结果例如function LessonInfo() { const lessonName JSX 与组件基础; const lessonCount 27; return ( p 你正在学习第 {lessonCount} 章{lessonName} /p ); }2. 花括号的本质是什么它不是字符串模板的替代品那么简单。更准确地说它是在告诉 React这里不是纯文本而是要放一个 JavaScript 表达式的结果。3. 当前阶段先别把事情搞太复杂你现在先做到两件事就够了会在 JSX 中渲染变量。会在 JSX 中渲染简单表达式。条件渲染、列表渲染、复杂事件逻辑后面章节会继续展开。十、在 JSX 中渲染变量其实就是“把数据放进界面里”React 里一个非常重要的过程就是把数据和界面对应起来。而 JSX 中最直接的第一步就是学会把变量放进界面。1. 先看一个完整但简单的例子function UserCard() { const userName 小白; const cityName 北京; const score 95; return ( section h2{userName}/h2 p所在城市{cityName}/p p本周练习得分{score}/p /section ); }这段代码想表达的事情很简单userName对应标题cityName对应一行说明score对应成绩信息这就是最基础的数据进入界面。2. 为什么这一步很重要因为以后你学到props、state、接口请求数据时核心都离不开这一步先有数据再把数据渲染到页面上。所以这一节虽然看起来简单但它其实是在给后面所有 React 数据流内容打基础。十一、在 JSX 中渲染简单列表的第一眼体验这一章我们不深入讲列表渲染规则但你可以先感受一下 JSX 是怎么把数组变成页面结构的。例如function SkillList() { const skillList [HTML, CSS, JavaScript]; return ( ul {skillList.map(function (skillName) { return li key{skillName}{skillName}/li; })} /ul ); }你现在先不用深究每个细节。这段代码当前阶段最值得观察的地方有两个数组里的每一项最后都能变成一个界面元素。JSX 不只是能写静态标签也能和 JavaScript 的数组方法配合。1. 这里为什么会出现map因为 React 里经常需要做这样的事情有一组数据就渲染出一组对应的界面内容。而map正好很适合表达“把一组数据转换成一组结果”。2. 这里为什么先写了key当前阶段你先知道一件事就够了当你渲染一组列表项时React 通常希望你为每项提供一个稳定标识。后面讲列表渲染时我们会专门把key讲透。现在你先把它当成列表渲染里的一个基础习惯即可。十二、什么是组件讲完 JSX我们就进入 React 的第二个核心概念组件。你现在可以先把组件理解成页面中的一个独立界面单元或者一个独立功能单元。例如下面这些内容都很适合被理解成组件顶部导航搜索栏用户卡片商品卡片课程列表页脚1. 为什么 React 特别强调组件因为现代前端页面很少是一整块单一内容。它更常见的状态是一个页面由很多小块结构组合而成。如果这些小块都混在一起写项目很容易越写越乱。而组件的价值就在于它能帮你把页面拆开、命名、组织、复用。2. 组件和普通 HTML 标签最大的区别是什么普通 HTML 标签像是divsectionbutton而 React 组件更像是PageHeaderProfileCardSkillList也就是说组件标签通常代表“你定义的一块界面能力”。这就是为什么它对组织页面特别重要。十三、函数组件的基本写法在现代 React 里初学阶段最常见、也最值得先掌握的组件形式就是函数组件。你可以先把它理解成用一个函数返回一段 JSX这个函数就是一个组件。先看一个最简单的例子function WelcomeCard() { return ( section h2欢迎学习 React/h2 p这一章我们正在学习 JSX 与组件基础。/p /section ); }1. 这段代码最值得先看懂什么先看三件事组件本质上是一个函数。这个函数返回的是 JSX。返回的 JSX 就是在描述界面。2. 为什么它叫“函数组件”因为它就是函数。只不过这个函数不是拿来计算总价、处理数组而是拿来生成并描述一块界面。3. 当前阶段最稳的理解方式你可以先把函数组件记成一句话组件就是一个返回 JSX 的函数。这句话虽然不覆盖所有高级场景但对于当前入门阶段非常够用。十四、为什么组件名通常要大写这一点初学者非常容易忽略但又非常重要。看下面两个写法function WelcomeCard() { return h2欢迎学习 React/h2; }WelcomeCard /这里的WelcomeCard首字母是大写的。1. 为什么要大写因为在 React 里首字母大写通常表示这是一个组件。而像下面这样的小写标签section /通常会被理解为原生标签。2. 这条规则为什么这么重要因为 React 需要根据标签形式区分这是浏览器原生标签。这是你自己定义的组件。所以你在写组件时最好一开始就养成规范习惯组件名使用有意义的英文名并且首字母大写。十五、组件是怎么被使用的定义好组件之后你就可以像使用标签一样去使用它。例如function WelcomeCard() { return h2欢迎学习 React/h2; } function App() { return ( main WelcomeCard / /main ); }这里发生的事情可以这样理解WelcomeCard是你自己定义的组件。App在自己的 JSX 里使用了它。页面最终会把这些组件组合成完整界面。这就是 React 非常重要的一层能力用组件去组合页面。十六、页面如何由多个组件组合而成这一节是从“单个组件”走到“页面结构”的关键一步。一个真实页面通常不会只靠一个组件完成。更常见的情况是App ├── PageHeader ├── IntroSection ├── SkillList └── PageFooter这棵树非常值得你慢慢看。它说明了一个很重要的事实React 页面通常不是一整块代码而是由多个组件按层级组合起来的。1. 看一个简单的组合例子function PageHeader() { return header从零开始学前端/header; } function IntroSection() { return section这一章我们学习 JSX 与组件基础。/section; } function App() { return ( main PageHeader / IntroSection / /main ); }2. 从这个例子里你要看到什么最值得你先看到的是页面被拆成了更小的结构块。每个结构块都有自己的名字和职责。App更像是在负责“组合页面”。这就是 React 组件组合的最基础思路。十七、组件拆分的基本原则这一节非常重要。因为很多初学者学到组件之后最容易出现两个极端什么都不拆所有内容都堆进App。拆得过碎一个小标题都想拆成独立组件。更稳的做法是按职责拆分而不是按代码行数拆分。1. 第一条原则看职责是否独立例如页头负责展示网站名称和导航卡片负责展示单个项目的信息列表负责组织多个卡片如果一块内容本身职责比较完整就很适合成为组件。2. 第二条原则看这块内容是否可能重复出现例如商品卡片课程卡片评论项用户信息卡片这类内容往往会重复出现很多次因此特别适合提炼成组件。3. 第三条原则看这块内容是否值得单独维护有些部分虽然不一定重复但它本身结构清楚、逻辑相对独立也值得拆出来。例如站点页头登录表单页脚说明4. 第四条原则先保证好懂再追求抽象这一点很关键。初学阶段最容易犯的错误之一就是为了“像会 React 一样”过早把组件拆得特别抽象。但如果拆完之后命名反而更模糊文件来回跳转更痛苦读代码的人更不容易看懂那这个拆分通常就不够好。所以请你先记住一句话好的组件拆分目标是让结构更清楚而不是让组件数量更多。十八、从旧页面到 React 组件应该怎么想如果你前面已经写过个人主页、待办事项页面或学生管理小工具那么这一节会特别有帮助。因为从原生页面切到 React最重要的转变之一就是不再只把页面看成一整页 HTML而是开始把它看成组件树。1. 先拿“个人主页页面”举例如果你之前用原生 HTML 写了一个个人主页它可能包含这些区域页面头部个人简介技能列表作品展示区联系方式区页脚如果换成 React 思维就可以先拆成App ├── PageHeader ├── ProfileIntro ├── SkillList ├── ProjectSection └── PageFooter2. 这一步最重要的不是马上写代码而是先学会做这件事给页面里的每一块职责起名字。因为一旦你能稳定地给结构命名组件思维就开始真正建立起来了。3. 后面还会继续往前走什么当前这一章我们先只做到会拆组件会写组件会组合组件再下一章你会继续看到组件之间的数据怎么传。那时候你就会真正开始理解为什么组件不只是“把页面拆开”而是“把界面结构和数据组织起来”。十九、一个简单的页面组件示例下面给你一个比较完整、但仍然适合入门阅读的小例子。function PageHeader() { return header从零开始学前端/header; } function ProfileIntro() { const userName 小白; return section你好我是 {userName}正在学习 React。/section; } function SkillList() { const skillList [HTML, CSS, JavaScript, TypeScript]; return ( ul {skillList.map(function (skillName) { return li key{skillName}{skillName}/li; })} /ul ); } function App() { return ( main PageHeader / ProfileIntro / SkillList / /main ); }1. 这个例子串起了哪些关键点它把这一章最核心的内容串到了一起JSX 长得像标签结构。组件本质上是返回 JSX 的函数。组件名首字母大写。变量可以通过{}放进界面。数组可以配合map渲染成一组列表项。页面可以由多个组件组合而成。2. 当前阶段你不需要一次吃透所有细节你现在只要能先看明白这几点就已经非常好了每个函数在负责一块界面。App负责把多个组件放到一起。界面内容不是写死的也可以由变量和数组生成。二十、初学者最常见的几个误区这一节你一定要看。很多 React 入门时的卡顿不是因为内容太难而是因为几个认知误区没及时纠正。1. 误区一把 JSX 当成普通 HTML这是最常见的误区。JSX 虽然像 HTML但你要记住它工作在 JavaScript 或 TypeScript 文件里。所以它会有自己的规则例如classNamehtmlFor花括号表达式组件标签2. 误区二组件拆分只看代码长短有些人会觉得超过几十行就拆不超过几十行就不拆。这种标准太机械。更合理的标准应该是这块内容是否有独立职责是否值得单独理解和维护。3. 误区三所有内容都堆在一个组件里初学阶段很容易把所有 JSX 都塞到App里。这在最早期练习没问题但只要页面稍微复杂一点马上就会变得很难读。所以你要慢慢养成习惯看到结构块就开始思考它是不是可以成为组件。4. 误区四为了显得高级把组件拆得特别碎另一个极端是把一切都拆成组件。例如一个只有一句话的小标签也非要独立成多个文件结果反而让结构更绕。所以还是那句话拆分的目标是让结构更清楚而不是让形式更复杂。5. 误区五一上来就追所有高级写法当前阶段你最重要的任务不是学完所有 Hook记住所有 API会写很多花哨技巧而是先把最基础的主线抓牢JSX 是什么组件怎么写页面怎么由组件组合起来这三件事一旦稳住后面的学习会轻松很多。二十一、本章实践练习这一章的练习重点不是追求功能复杂而是建立“组件化写界面”的第一层手感。1. 练习 1写出你的第一个App组件请你创建一个最简单的 React 页面要求包含一个页面标题一段学习说明文字一个技能列表你可以参考这样的结构App ├── 标题 ├── 说明文字 └── 技能列表这个练习的重点是先熟悉 JSX 和组件返回界面的基本感觉。2. 练习 2把个人主页页面拆成组件树请不要急着写完整代码先做结构拆分找出页面有哪些区域。给每个区域起一个组件名。画出组件树。例如App ├── PageHeader ├── ProfileIntro ├── SkillList ├── ProjectSection └── PageFooter这个练习非常关键。因为它在训练你从“整页 HTML 思维”切到“组件树思维”。3. 练习 3在组件里渲染变量请你写一个组件在界面里展示你的名字你的学习阶段你已经学过的章节数目标不是复杂而是熟悉如何把变量通过{}放进 JSX。4. 练习 4在组件里渲染一个简单列表请你准备一组数组数据例如你会的技术名称你想练习的项目名称你本周要完成的任务然后在 JSX 中把它渲染成一个列表。这个练习会让你开始建立数据如何变成一组页面元素。二十二、学习重点提示这一章请你重点记住下面这些话JSX 看起来像 HTML但本质上是 JavaScript 的语法扩展。JSX 的核心价值是让界面结构的描述更自然、更直观。组件最基础的形式可以先理解为“返回 JSX 的函数”。组件名通常使用有意义的名称并以大写字母开头。在 JSX 中放变量和表达式时通常使用花括号{}。页面不是一整块代码而是由多个有职责的组件组合而成。组件拆分标准应围绕职责而不是围绕代码行数。初学 React 时先把 JSX 和组件基础学扎实比急着追高级 API 更重要。如果你只记一句话请记住JSX 负责描述界面组件负责组织界面而 React 页面就是由组件组合起来的界面树。二十三、本章小结这一章我们正式从“理解 React 为什么重要”迈进了“开始写 React 基础代码”的阶段。你已经理解了JSX 是什么JSX 和普通 HTML 的关系JSX 最常见的基础语法特点如何在 JSX 中渲染变量和简单列表什么是组件函数组件最基础的写法页面为什么会由多个组件组合而成组件拆分时为什么要围绕职责来思考更重要的是你已经开始建立一种全新的页面理解方式页面不是一整页散落的结构和逻辑而是由多个组件组成的界面树。这一步非常关键。因为后面当你学习Props时你就会看到组件不仅能被拆出来还能彼此传递数据、形成更清楚的页面结构关系。二十四、课后思考题请你认真思考下面几个问题为什么说 JSX 看起来像 HTML但不能简单等同于 HTMLJSX 中为什么需要花括号{}为什么组件名通常要用大写开头页面拆分组件时为什么不能只按代码行数来决定为什么说 React 页面更像一棵组件树如果把所有内容都堆在App里后面项目可能会遇到什么问题建议你把这些问题用自己的话写下来。只要你能把这些问题讲清楚就说明你已经真正开始进入 React 的编码思维了。二十五、下一篇预告下一章我们会进入从零开始学前端 | 第二十八章Props 与组件复用到那时你会继续解决一个非常关键的问题组件拆开之后它们之间的数据该怎么传你会开始学习什么是Props父组件怎么给子组件传值为什么Props是组件复用的基础如何把“写死的组件”慢慢变成“可配置的组件”也就是说下一章开始我们会从“会写组件”继续走到让组件真正具备复用价值。