跟着 MDN 学 React 框架 Day 3:React 入门——核心概念与第一个应用
摘要本文是 React 入门学习的第三日记录内容源于 MDN Web 文档的官方指南。我们将从 React 的核心理念出发探讨它作为用户界面库的定位及其在现代 Web 开发中的用例。文章将详细解析 React 如何利用 JSX 语法在 JavaScript 中优雅地描述 HTML 结构并通过 create-react-app 工具链一步步带领读者从零搭建本地开发环境。最后我们将深入剖析初始应用的结构理解第一个组件App/的工作原理并掌握 JSX 中变量和 Props 的使用技巧为后续开发打下坚实基础。一、你好 React一个用于构建用户界面的库React 的官方口号非常明确它是一个用于构建用户界面的 JavaScript 库。理解库而非框架这一定位至关重要。框架通常提供一套完整的解决方案强制规定代码组织、路由、数据流等方方面面的规则而 React 则专注于做好一件事——构建 UI。它的应用范围并不局限于 Web 页面通过与不同的渲染器结合React 可以大展拳脚。例如React Native 能够让开发者使用 React 语法构建原生移动应用而 React 360 则将 React 带入了虚拟现实领域。对于 Web 开发而言开发者通常将 React 与 ReactDOM 协同使用。React 负责核心逻辑而 ReactDOM 负责将 React 构建的 UI 渲染到浏览器环境中。正因如此在日常口语化交流中我们常将 React 与 ReactDOM 的组合统称为一个框架因为它们确实解决了与传统框架相同的问题。React 的核心设计目标是最大限度地减少开发者在构建 UI 时引入的错误。它达成这一目标的关键机制就是组件。组件是自包含的、描述部分用户界面的逻辑代码段。它们就像乐高积木一样可以独立开发、测试然后组合在一起构建出复杂完整的用户界面。React 将底层的渲染、状态更新等复杂工作进行了抽象让开发者能够更专注于 UI 设计本身而不是繁琐的 DOM 操作。二、用例从微小部件到完整应用与本模块中介绍的其他框架不同React 并不对代码约定或文件组织结构强加严格的规则。这种灵活性赋予了团队极大的自主权他们可以根据项目特点与自身偏好制定最适合的约定以任何方式采用 React。React 可以处理一个简单的按钮也可以管理一个界面的几个部分甚至能够承载起整个应用程序的用户界面。尽管 React 理论上可以像 jQuery 或 Vue 那样被引入到页面的某个局部来替换一小块 UI但在实际开发中这并不容易。React 的许多优势尤其是其基于组件的架构和强大的状态管理能力在用它构建整个应用时才能得到充分体现。部分引入的方式反而会增加复杂性。此外使用 React 通常意味着需要拥抱现代前端工具链。一个典型的例子是 JSX。JSX 是一种 JavaScript 的语法扩展它允许我们在 JavaScript 代码中直接编写类似 HTML 的标记。但浏览器无法直接解析 JSX必须经过一个编译步骤将其转换为标准的 JavaScript 函数调用即React.createElement()。在网站上直接添加一个像 Babel 这样的实时编译器会严重影响页面性能。因此开发人员通常会在构建阶段就设置好这类工具提前将 JSX 编译成高效的 JavaScript 代码。这个过程对工具链的要求虽然较高但带来的开发体验和运行效率提升是值得学习的。本文将聚焦于一个最主流的用例利用 Facebook 官方提供的 create-react-app 脚手架工具创建一个用于渲染整个应用用户界面的 React 项目。三、React 如何使用 JavaScript——JSX 的魅力React 的许多设计模式都深度运用了现代 JavaScript 的特性但与原生 JavaScript 最直观的区别在于 JSX 语法的使用。JSX 是 JavaScript 和 XML 的结合体它让类似 HTML 的代码能够与 JavaScript 逻辑共存极大地提升了代码的可读性和编写效率。一个简单的 JSX 表达式如下const heading h1Mozilla Developer Network/h1;这段代码不是字符串也不是 HTML它就是 JSX。React 可以使用这个heading常量直接在应用中渲染一个h1标签。如果出于语义化考虑我们想将这个标题包裹在header标签内JSX 允许我们像写 HTML 一样自然地进行元素嵌套const header ( header h1Mozilla Developer Network/h1 /header );请注意代码外层的括号并非 JSX 语法的一部分它只是一个纯粹的分隔符用于向开发者和格式化工具明确表示括号内的多行代码属于同一个表达式。这在编写多行 JSX 时非常有用避免了因为缩进问题导致的歧义。浏览器无法直接读取并理解 JSX。上面的header表达式在经过 Babel 或 Parcel 等编译工具的转换后会变成如下形式constheaderReact.createElement(header,null,React.createElement(h1,null,Mozilla Developer Network));我们当然可以完全跳过编译步骤直接使用React.createElement()来手写 UI但这将完全丧失 JSX 带来的声明式、直观的编写优势代码会变得异常复杂且难以阅读。编译是开发流程中的一个额外环节但 React 社区普遍认为JSX 带来的可读性收益远超其成本。流行的工具链已经将 JSX 到 JavaScript 的编译集成进了设置过程除非有特殊需求开发者无需手动配置。对于 JSX 这种混合特性一些开发者觉得直观另一些可能觉得混乱。但不可否认的是一旦熟悉它构建用户界面的速度和直观性都会显著提升同时也能让团队成员更轻松地理解代码库的结构和意图。四、设置你的第一个 React 应用使用 create-react-app有多种方式可以将 React 集成到项目中但 create-react-app 命令行工具是官方推荐的最便捷的起点。它通过安装一系列精心配置的软件包并生成一套标准化的项目文件结构极大地加速了 React 应用的启动过程让开发者能将更多时间花在业务逻辑构建上而非环境配置。要求在开始之前你需要确保电脑上安装了 Node.js推荐使用长期支持LTS版本。Node.js 会附带 npm包管理器和 npx包运行器。你也可以选择 Yarn 作为替代的包管理器但本教程假设使用 npm。如果你使用的是 Windows 系统为了能顺利运行本教程中的终端命令建议安装 Gitbash 或 Linux 的 Windows 子系统以获得与 Unix/macOS 终端一致的操作体验。还需要注意的是React 和 ReactDOM 生成的应用程序默认支持一组相当现代的浏览器通过一些 polyfill 可以兼容到 IE9。在进行学习时建议使用 Firefox、Safari 或 Chrome 等现代浏览器以获得最佳体验。初始化你的应用create-react-app 命令接受一个参数即你为应用设定的名称。它会创建一个同名的文件夹并在其中生成所有必需的文件。请打开命令行终端进入你希望存放项目的文件夹然后执行以下命令npx create-react-app moz-todo-react这条命令会创建一个名为moz-todo-react的文件夹并自动完成以下几项关键工作为你的应用安装所有必需的 npm 包。写入启动、构建、测试等 React 应用所需的脚本。创建一系列结构化的子文件夹和文件奠定应用程序的基础架构。如果你的电脑上安装了 git它会自动初始化一个 Git 仓库。如果你同时安装了 Yarn 和 npm但希望强制使用 npm可以在命令后加上--use-npm参数npx create-react-app moz-todo-react --use-npm执行过程可能需要几分钟终端会显示一些状态信息。命令执行完毕后进入项目文件夹并启动开发服务器cdmoz-todo-reactnpmstart该命令会启动一个本地开发服务器通常在http://localhost:3000地址上运行并自动在默认浏览器中打开这个地址。如果一切顺利你会看到一个 React 欢迎页面。五、探索第一个 React 组件 —App/create-react-app 生成的项目结构中最核心的源码目录是src。其中src/App.js文件包含了我们接触到的第一个也是最重要的根组件App。打开它其内容如下importReactfromreact;importlogofrom./logo.svg;import./App.css;functionApp(){return(div classNameAppheader classNameApp-headerimg src{logo}classNameApp-logoaltlogo/pEditcodesrc/App.js/codeand save to reload./pa classNameApp-linkhrefhttps://reactjs.orgtarget_blankrelnoopener noreferrerLearn React/a/header/div);}exportdefaultApp;这个文件清晰地展示了 React 组件的三个典型组成部分顶部的导入语句中间的函数式组件定义以及底部的导出语句。导入语句importReactfromreact;importlogofrom./logo.svg;import./App.css;这三行导入分别代表了三种不同的模块导入场景。第一行从名为react的 npm 包中导入 React 核心对象。这是任何包含 JSX 的模块所必需的因为 JSX 最终会被转换为React.createElement调用。第二行导入一个本地的 SVG 文件并将其赋值给logo变量。以./开头的路径表明这是一个相对于当前文件的本地模块。第三行直接导入一个 CSS 文件这种语法不将其赋给任何变量它是 webpack 这类模块打包器提供的特性能将 CSS 注入到应用中。App 组件组件的主体是一个名为App的普通 JavaScript 函数。请注意React 的组件名必须使用帕斯卡命名法PascalCase即首字母大写如App、UserProfile以便在 JSX 中与普通的 HTML 标签如div区分开来。如果函数名是小写的React 会将其视为一个普通的 HTML 元素从而导致错误。该函数返回一个 JSX 表达式这个表达式精确地描述了浏览器最终要渲染的 DOM 结构。仔细观察这个 JSX你会发现一些与标准 HTML 不同的地方例如div标签的属性是className而非class。这是因为class是 JavaScript 的保留关键字JSX 作为 JavaScript 的扩展为了避免冲突便使用了className。类似地许多 HTML 属性在 JSX 中都采用了驼峰式命名。现在我们可以尝试对组件进行简单修改。将p标签的内容改为 “Hello, world!”然后保存文件。浏览器页面会立即自动刷新显示新的文本。接着删除整个a标签并保存页面上 “Learn React” 的链接也会随之消失。这种热更新机制是 React 开发体验中非常重要的一环。修改后的App组件如下functionApp(){return(div classNameAppheader classNameApp-headerimg src{logo}classNameApp-logoaltlogo/pHello,World!/p/header/div);}Export 语句文件最底部的export default App语句是关键。它使得App组件能够被其他 JavaScript 模块导入和使用是 React 组件化和模块化的基石。没有它App组件将是一个私有的函数无法在外部使用。六、审查入口文件初识渲染机制现在让我们打开src/index.js文件它是整个 React 应用的入口点。初始内容如下importReactfromreact;importReactDOMfromreact-dom;import./index.css;importAppfrom./App;import*asserviceWorkerfrom./serviceWorker;ReactDOM.render(App/,document.getElementById(root));serviceWorker.unregister();与App.js类似文件顶部进行了必要的模块导入。关键点在于它从./App路径导入了我们刚刚创建的App组件。正是因为App.js底部有export default App这里的import App from ./App才能成功执行。最核心的一行代码是ReactDOM.render(App/,document.getElementById(root));ReactDOM.render()函数接收两个参数要渲染的 React 元素这里使用的是App /它是一个 JSX 标签代表我们的根组件。注意像App /这样的自闭合标签是必需的缺少闭合斜杠会导致错误。目标 DOM 容器这里通过原生 JavaScript 方法获取了 ID 为root的 DOM 元素。这个元素可以在public/index.html文件中找到它是 React 应用挂载并渲染整个组件树的根节点。整行代码的含义就是React请获取App组件所描述的 UI并将其渲染到 HTML 页面中 ID 为root的div容器里。关于serviceWorker的代码用于实现离线缓存等 PWA 特性不在本入门讨论范围内可以暂时忽略或删除。七、变量与 Props让组件动起来现在我们将学习如何利用 JavaScript 的变量和 React 特有的 Props 机制让组件处理动态数据使其更具灵活性和复用性。JSX 中的变量回到App.js请看这行代码img src{logo} classNameApp-logo altlogo /这里src属性的值被包裹在一对大括号{}中。在 JSX 语法中大括号是通往 JavaScript 世界的传送门。任何有效的 JavaScript 表达式都可以放在大括号内React 会计算其值并嵌入到生成的 HTML 中。这里的{logo}告诉 React 去查找第二行导入的logo变量并将其值即 SVG 文件的路径作为src属性的值。我们可以定义自己的变量。在App函数的return语句之前添加一行const subject React;。然后将p标签中的文本修改为使用该变量function App() { const subject React; return ( div classNameApp header classNameApp-header img src{logo} classNameApp-logo altlogo / pHello, {subject}!/p /header /div ); }保存后浏览器会显示 “Hello, React!”。这就是在 JSX 中使用变量的基本方式。组件 Props变量非常方便但它定义在组件内部是静态的。如何从外部向组件传递数据呢这就需要用到 Props。PropsProperties 的缩写是传入 React 组件的、只读的参数集合。它的用法和编写 HTML 属性非常相似。首先我们在index.js中为App /组件传入一个名为subject的 propReactDOM.render(App subjectClarice /, document.getElementById(root));现在App组件就收到了一个名为subject、值为Clarice的数据。为了在组件内部访问它我们需要修改App函数的签名让它接收一个props参数。function App(props) { const subject props.subject; return ( div classNameApp header classNameApp-header img src{logo} classNameApp-logo altlogo / pHello, {subject}!/p /header /div ); }所有传递给组件的 props 都会被 React 自动收集到一个名为props的对象中该对象会作为函数的第一个参数传入。props.subject的值正是我们在index.js中设置的Clarice。现在页面上就会渲染出 “Hello, Clarice!”。如果我们回到index.js修改subject的值为其他字符串页面文本也会随之改变。这展示了 Props 的核心作用让父组件此处是index.js中的逻辑能够配置和传递数据给子组件App组件实现了组件的动态化和可复用性。总结本文通过 MDN 的官方指南系统性地入门了 React。我们首先理解了 React 作为一个专注 UI 的库的定位及其通过组件化来最小化开发错误的目标。接着我们分析了 React 的用例它更适合构建完整的应用并通常需要现代化的工具链支持。文章的核心部分深入探讨了 JSX 语法它是 React 与 JavaScript 结合的关键通过编译过程实现了声明式的 UI 构建。随后我们通过 create-react-app 成功搭建了第一个 React 应用环境并剖析了其目录结构。我们重点研究了App组件的内部构造包括导入/导出机制、PascalCase 命名法和 JSX 中特殊的属性名。在入口文件index.js中我们了解了ReactDOM.render()如何将根组件挂载到 DOM。最后我们掌握了在 JSX 中使用变量的方法并学习了 Props 这一核心机制实现了父组件向子组件传递数据的功能。回顾一下本次学习的关键点React 组件通过import引入依赖并通过export default暴露自身。组件名称必须使用帕斯卡命名法PascalCase。在 JSX 中通过将变量包裹在{}中来访问其值如{variable}。部分 HTML 属性在 JSX 中名称不同如class写作className属性名遵循驼峰命名法。Props属性像 HTML 属性一样写在组件标签上所有 props 会被打包成一个对象作为组件函数的第一个参数用于从父组件向子组件传递数据。到此React 的基础知识框架已经建立。掌握了这些我们就可以在下一篇文章中开始动手创建第一个真正的交互式应用——一个任务清单程序继续我们的 React 学习之旅。