域名 AXUM.RS 将于2025年10月到期。我们无意再对其进行续费,我们希望你能够接续这个域名,让更多 AXUM 开发者继续受益。现在,我们已启用新域名 AXUM.EU.ORG
  • 方案AXUM.RS 域名 = 3000
如果你有意接续这份 AXUM 情怀,请与我们取得联系。
说明:
  1. 如果有人购买 AXUM.RS 域名,或者该域名到期,本站将使用免费域名 AXUM.EU.ORG 继续提供服务。

React: 简介与安装

本章将通过编程世界通用的“Hello World”程序,告诉你:创建 React 应用的几种方法、虚拟DOM、JSX以及将 React 挂载到真实 DOM 的步骤。

本专题是快速入门级别的,如果你想深入、完整的学习 React,这里推荐尚硅谷的免费 React 视频教程(为了不分散你的注意力,该教程的链接地址将在专题结束之后放出),以及 React官方文档(中文)

本专题或多或少引用了以上两个资源的部分内容,在此一并表示感谢。

本专题是快速入门级别的,如果你想深入、完整的学习 React,这里推荐尚硅谷的免费 React 视频教程(为了不分散你的注意力,该教程的链接地址将在专题结束之后放出),以及 React官方文档(中文)

本专题或多或少引用了以上两个资源的部分内容,在此一并表示感谢。

在开始之前,我们先来了解几个概念。

DOM 与虚拟DOM

你应该知道什么是 DOM,如果感觉不是很能清楚描述,可以看看这个文档的描述。我们重点关注虚拟DOM(Virtual DOM,VDOM)。

React 官网的描述是:

Virtual DOM 是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。这一过程叫做协调

这种方式赋予了 React 声明式的 API:您告诉 React 希望让 UI 是什么状态,React 就确保 DOM 匹配该状态。这使您可以从属性操作、事件处理和手动 DOM 更新这些在构建应用程序时必要的操作中解放出来。

与其将 “Virtual DOM” 视为一种技术,不如说它是一种模式,人们提到它时经常是要表达不同的东西。在 React 的世界里,术语 “Virtual DOM” 通常与 React 元素关联在一起,因为它们都是代表了用户界面的对象。而 React 也使用一个名为 “fibers” 的内部对象来存放组件树的附加信息。上述二者也被认为是 React 中 “Virtual DOM” 实现的一部分。

Virtual DOM 是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。这一过程叫做协调

这种方式赋予了 React 声明式的 API:您告诉 React 希望让 UI 是什么状态,React 就确保 DOM 匹配该状态。这使您可以从属性操作、事件处理和手动 DOM 更新这些在构建应用程序时必要的操作中解放出来。

与其将 “Virtual DOM” 视为一种技术,不如说它是一种模式,人们提到它时经常是要表达不同的东西。在 React 的世界里,术语 “Virtual DOM” 通常与 React 元素关联在一起,因为它们都是代表了用户界面的对象。而 React 也使用一个名为 “fibers” 的内部对象来存放组件树的附加信息。上述二者也被认为是 React 中 “Virtual DOM” 实现的一部分。

叭啦叭啦一大堆,说了又好像没完全说,这就是官网的统一气质。我们对这段晦涩难懂的文字进行归纳:

  • VDOM是一种概念,是一种模式
  • 正如其名,VDOM是虚拟,它是被保存在内存中的
  • VDOM最终会与真实DOM同步,也就是说,最终会变成真实DOM呈现在页面上
  • VDOM通过状态改变UI的呈现

而尚硅谷的视频教程里,也做出了小结:

  • VDOM 本质是 Object 类型的对象(一般对象)
  • 虚拟 DOM 比较“轻”,真实 DOM 比较“重”。因为虚拟 DOM 是 React 内部在用,无需真实 DOM 上那么多属性。
  • 虚拟 DOM 最终会被 React 转化为真实 DOM,呈现在页面上。

JSX

我们先来看一下 JSX 长什么样:

const element = <h1>Hello, world!</h1>;
  • 它不是字符串,因为没有被引号包裹
  • 它更像是 HTML 标签,但它直接放在了 JavaScript 代码里

JSX 是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模板语言,但它具有 JavaScript 的全部功能。

JSX 是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模板语言,但它具有 JavaScript 的全部功能。

  • JSX 是看起来很像 HTML 的东西

  • 它允许直接作为 Javascript 的表达式

  • 它可以直接嵌入Javascript表达式,如下:

    const name = 'axum.rs';
    const element = <h1>你好,{name}</h1>;
    
  • 它其实是语法糖—— React.createElement() 的语法糖

JSX 是看起来很像 HTML 的东西

它允许直接作为 Javascript 的表达式

它可以直接嵌入Javascript表达式,如下:

const name = 'axum.rs';
const element = <h1>你好,{name}</h1>;

它其实是语法糖—— React.createElement() 的语法糖

规范

JSX 虽然看起来像 HTML (其实和 XHTML/XML 的表现更像),但它有一些规范需要遵守:

  • 必须闭合。比如,在 HTML 中,<img> 是没有闭合标签的,JSX 要求所有标签必须闭合,所以可以在标签最后加上 /,变成 <img />,比如:(这个规则适用于所有没有或者不需要闭合的标签,包括 HTML 中的 <br />, <hr /> 等,也包括自定义组件)

    const img = <img src="axum-rs-logo.png" alt="AXUM中文网" />;
    
  • 在 VDOM 中,必须有且只有一个根标签

    // 错误
    const element = <h1>标题</h1><p>内容</p>;
    
    // 正确
    const element = <div><h1>标题</h1><p>内容</p></div>;
    

    <h1>标题</h1><p>内容</p> 是两个标签,它们不能直接作为根标签放在 VDOM。而是需要将它们包裹在一个标签里。

  • 通过 {} 可以在 JSX 里插入 JavaScript 表达式。

  • 属性名使用小驼峰命名。HTML 里有许多属性是带中线分割的,比如:data-site="axum.rs",在 JSX 中,需要变成:dataSite="axum.rs"

  • 部分重命名的属性。由于 JSX 的本质是语法糖,它其实调用的是一个 Javascript 函数,所以它自身最终也会被转换成 Javascript 代码。对于有些和Javascript关键字同名的 HTML 属性,JSX对它们进行了重新命名:

必须闭合。比如,在 HTML 中,<img> 是没有闭合标签的,JSX 要求所有标签必须闭合,所以可以在标签最后加上 /,变成 <img />,比如:(这个规则适用于所有没有或者不需要闭合的标签,包括 HTML 中的 <br />, <hr /> 等,也包括自定义组件)

const img = <img src="axum-rs-logo.png" alt="AXUM中文网" />;

在 VDOM 中,必须有且只有一个根标签

// 错误
const element = <h1>标题</h1><p>内容</p>;

// 正确
const element = <div><h1>标题</h1><p>内容</p></div>;

<h1>标题</h1><p>内容</p> 是两个标签,它们不能直接作为根标签放在 VDOM。而是需要将它们包裹在一个标签里。

通过 {} 可以在 JSX 里插入 JavaScript 表达式。

属性名使用小驼峰命名。HTML 里有许多属性是带中线分割的,比如:data-site="axum.rs",在 JSX 中,需要变成:dataSite="axum.rs"

部分重命名的属性。由于 JSX 的本质是语法糖,它其实调用的是一个 Javascript 函数,所以它自身最终也会被转换成 Javascript 代码。对于有些和Javascript关键字同名的 HTML 属性,JSX对它们进行了重新命名:

HTML属性JSX属性
classclassName
forhtmlFor
  • 标签的首字母决定了类型

    • 若首字母小写,则转换为 HTML 中同名元素。若 HTML 中没有对应的同名元素则报错
    • 若首字母大写,则视为组件, React 会去渲染对应的组件。如果没有对应的组件,则报错
    // 将视为 HTML 的 <h1> 标签
    const element = <h1>你好,axum.rs</h1>; 
    
    // 将视为渲染 <H1> 组件
    const element = <H1>你好,axum.rs</H1>; 
    
  • 内联样式的写法。在 HTML 中,可以通过 style 来定义内联样式,它的值是一堆键值对。在JSX中,需要使用 style={{key1:value1,key2:value2}} 的写法。

    • 虽然本质很简单,但这么多括号难免让人头晕。这里解释一下:

    • style={} 表示style属性的值是一个JAVASCRIPT表达式

    • {key1:value1,key2:value2}这是一个典型的 Javascript 语法——简单对象:

      const obj = {key1:value1,key2:value2};
      
    • 所以,整个写法的意思是,需要把一个JAVASCRIPT 的 Object 作为 style 属性的值

标签的首字母决定了类型

  • 若首字母小写,则转换为 HTML 中同名元素。若 HTML 中没有对应的同名元素则报错
  • 若首字母大写,则视为组件, React 会去渲染对应的组件。如果没有对应的组件,则报错
// 将视为 HTML 的 <h1> 标签
const element = <h1>你好,axum.rs</h1>; 

// 将视为渲染 <H1> 组件
const element = <H1>你好,axum.rs</H1>; 

内联样式的写法。在 HTML 中,可以通过 style 来定义内联样式,它的值是一堆键值对。在JSX中,需要使用 style={{key1:value1,key2:value2}} 的写法。

  • 虽然本质很简单,但这么多括号难免让人头晕。这里解释一下:

  • style={} 表示style属性的值是一个JAVASCRIPT表达式

  • {key1:value1,key2:value2}这是一个典型的 Javascript 语法——简单对象:

    const obj = {key1:value1,key2:value2};
    
  • 所以,整个写法的意思是,需要把一个JAVASCRIPT 的 Object 作为 style 属性的值

style={} 表示style属性的值是一个JAVASCRIPT表达式

{key1:value1,key2:value2}这是一个典型的 Javascript 语法——简单对象:

所以,整个写法的意思是,需要把一个JAVASCRIPT 的 Object 作为 style 属性的值

你好,React

讲了这么多理论,终于可以来体验一把了。

有很多创建 React 应用的方法,下面一一进行介绍。

通过CDN的方式

这是最简单的方法,通过这个方法可以直接在页面中使用 React。

但是这是最不推荐的方法,请不要在正式环境使用此方法。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>axum中文网</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/umd/react.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.production.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@babel/[email protected]/babel.min.js"></script>
    <script type="text/babel">
      const VDOM = <h1>你好,axum.rs!</h1>;
      const root = ReactDOM.createRoot(document.getElementById("root"));
      root.render(VDOM);
    </script>
  </body>
</html>

除了一堆 <script>,你会发现只有一个 idrootdiv

  • 第10行:引入 react
  • 第11行:引入react-dom
  • 第12行:引入babel:用于将 JSX 转换成普通的 JS 代码
  • 第13行:注意,type="text/babel",这样才能正确编写 JSX 代码,并让 babel 转换成普通 JS 代码
  • 【定义入口VDOM】第14行:声明一个变量 VDOM,它的值是一个 JSX
  • 【定义React根元素】第15行:声明一个变量 root,它通过 ReactDOM.createRoot() 来创建 React 根元素;它的参数是一个真实 DOM,即我们在第9行的 HTML 中的 id="root"div
  • 【渲染VDOM】第16行:调用 rootrender() 方法,将 VDOM 渲染到真实 DOM 中

通过官方的 create-react-app

React 提供了一个名为 create-react-app 的工具,用于创建 React 应用的脚手架。它使用 webpack 作为打包工具,所以就——很慢、很笨重。

方式一:全局安装

在使用这个脚手架工具之前,你需要首先全局安装这个工具:

npm install -g create-react-app

然后创建我们的应用:

create-react-app 应用名字

比如:

create-react-app hello-react

它需要很长的一段时间,耐心等待吧。

创建完成之后,进入到新创建项目所在文件夹:

cd hello-react

方式二:yarn create

相较于全局安装,我更喜欢使用 yarn create 的方式。这是 yarn 提供的功能,它本质还是调用 create-react-app,只不过它不需要手动去全局安装。

yarn create react-app hello-react

等待创建完成,然后进入所在目录:

cd hello-react

目录结构

├── README.md
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html -- 静态页面
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js -- 主组件
    ├── App.test.js
    ├── index.css
    ├── index.js -- 入口文件
    ├── logo.svg
    ├── reportWebVitals.js
    └── setupTests.js
  • public/index.html:静态页面,提供 React 挂载容器。这个文件很多内容,我们把它精减一下:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>React App</title>
      </head>
      <body>
        <div id="root"></div>
      </body>
    </html>
    
    • 第10行:<div id="root"></div>,我们的 React 虚拟 DOM 最终将挂载在这个元素上,并渲染为真实 DOM
  • src/index.js:项目入口文件

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './index.css';
    import App from './App';
    import reportWebVitals from './reportWebVitals';
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    );
    
    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals();
    
    • 第1行:引入 React
    • 第2行:引入 ReactDOM
    • 第3行:引入样式
    • 第4行:引入主组件 App
    • 第5行:引入 reportWebVitals,用于性能分析。对于我们来说,直接忽略——你可以直接删除它(同时删除第17行的调用)
    • 第7行:声明一个变量 root,它通过 ReactDOM.createRoot() 来创建 React 根元素;它的参数是一个真实 DOM,即我们在 HTML 中的 id="root"div
    • 第8~12行:渲染虚拟DOM
      • 第9~11行:使用 React.StrictMode组件。它是 React 内置的组件,用于开启严格模式
      • 第10行:使用 App 主组件。注意闭合
    • 第17行:性能分析的函数调用。对于我们来说,直接忽略——你可以直接删除它(同时删除第5行的引入)
  • src/App.js:主组件。定义主组件App。它生成的代码对于现在你来说可能过于复杂,让我们把它改成以下内容:

    import React from "react";
    
    function App() {
      return <h1>你好,AXUM中文网</h1>;
    }
    
    export default App;
    
    • 第1行:引入 React
    • 第3~5行:声明一个函数,它的名字叫 App
      • 第4行:它的返回值是一个 JSX
      • 注意,它其实是一个 React 组件:
        • 首字母大小
        • 返回 JSX
    • 第7行:将 App 组件作为默认导出

public/index.html:静态页面,提供 React 挂载容器。这个文件很多内容,我们把它精减一下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
  • 第10行:<div id="root"></div>,我们的 React 虚拟 DOM 最终将挂载在这个元素上,并渲染为真实 DOM

src/index.js:项目入口文件

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
  • 第1行:引入 React
  • 第2行:引入 ReactDOM
  • 第3行:引入样式
  • 第4行:引入主组件 App
  • 第5行:引入 reportWebVitals,用于性能分析。对于我们来说,直接忽略——你可以直接删除它(同时删除第17行的调用)
  • 第7行:声明一个变量 root,它通过 ReactDOM.createRoot() 来创建 React 根元素;它的参数是一个真实 DOM,即我们在 HTML 中的 id="root"div
  • 第8~12行:渲染虚拟DOM
    • 第9~11行:使用 React.StrictMode组件。它是 React 内置的组件,用于开启严格模式
    • 第10行:使用 App 主组件。注意闭合
  • 第17行:性能分析的函数调用。对于我们来说,直接忽略——你可以直接删除它(同时删除第5行的引入)
  • 第9~11行:使用 React.StrictMode组件。它是 React 内置的组件,用于开启严格模式
  • 第10行:使用 App 主组件。注意闭合

src/App.js:主组件。定义主组件App。它生成的代码对于现在你来说可能过于复杂,让我们把它改成以下内容:

import React from "react";

function App() {
  return <h1>你好,AXUM中文网</h1>;
}

export default App;
  • 第1行:引入 React
  • 第3~5行:声明一个函数,它的名字叫 App
    • 第4行:它的返回值是一个 JSX
    • 注意,它其实是一个 React 组件:
      • 首字母大小
      • 返回 JSX
  • 第7行:将 App 组件作为默认导出
  • 第4行:它的返回值是一个 JSX
  • 注意,它其实是一个 React 组件:
    • 首字母大小
    • 返回 JSX
  • 首字母大小
  • 返回 JSX

运行和构建

# 运行
yarn start

# 构建
yarn build

通过 vite

虽然 create-react-app 是官方的,但它实在是太笨重了,而 vite 提供了更轻量的解决方案。【在线体验】👉本教程将使用 vite 来创建 React 项目。

yarn create vite hello-react --template react

目录结构

├── index.html -- 静态页面
├── package.json
├── public
│   └── vite.svg
├── src
│   ├── App.css
│   ├── App.jsx -- 主组件
│   ├── assets
│   │   └── react.svg
│   ├── index.css
│   └── main.jsx -- 入口
└── vite.config.js
  • index.html:静态页面,提供 React 挂载容器。

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Vite + React</title>
      </head>
      <body>
        <div id="root"></div>
        <script type="module" src="/src/main.jsx"></script>
      </body>
    </html>
    
    • 第10行:<div id="root"></div>,我们的 React 虚拟 DOM 最终将挂载在这个元素上,并渲染为真实 DOM
    • 第11行:引入 src/main.jsx
  • src/main.jsx:入口文件

    import React from 'react'
    import ReactDOM from 'react-dom/client'
    import App from './App'
    import './index.css'
    
    ReactDOM.createRoot(document.getElementById('root')).render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    )
    
    • 第1行:引入 React
    • 第2行:引入 ReactDOM
    • 第3行:引入主组件 App
    • 第4行:引入样式文件
    • 第6~10行:创建React根元素,并渲染
      • 第7行和第9行:使用 React.StrictMode 组件。它是由 React 内置的组件,用于开启严格模式
      • 第8行:使用App 主组件,注意闭合
  • src/App.jsx:主组件:定义主组件 App,它生成的代码对于现阶段的你来说可能太复杂了,让我们把它简化成以下内容:

    import React from 'react'
    
    function App() {
      return <h1>你好,axum.rs!</h1>
    }
    
    export default App
    
    • 第1行:引入 React
    • 第3~5行:声明一个函数,它的名字叫 App
      • 第4行:它的返回值是一个 JSX
      • 注意,它其实是一个 React 组件:
        • 首字母大小
        • 返回 JSX
    • 第7行:将 App 组件作为默认导出

index.html:静态页面,提供 React 挂载容器。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>
  • 第10行:<div id="root"></div>,我们的 React 虚拟 DOM 最终将挂载在这个元素上,并渲染为真实 DOM
  • 第11行:引入 src/main.jsx

src/main.jsx:入口文件

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)
  • 第1行:引入 React
  • 第2行:引入 ReactDOM
  • 第3行:引入主组件 App
  • 第4行:引入样式文件
  • 第6~10行:创建React根元素,并渲染
    • 第7行和第9行:使用 React.StrictMode 组件。它是由 React 内置的组件,用于开启严格模式
    • 第8行:使用App 主组件,注意闭合

src/App.jsx:主组件:定义主组件 App,它生成的代码对于现阶段的你来说可能太复杂了,让我们把它简化成以下内容:

import React from 'react'

function App() {
  return <h1>你好,axum.rs!</h1>
}

export default App
  • 第1行:引入 React
  • 第3~5行:声明一个函数,它的名字叫 App
    • 第4行:它的返回值是一个 JSX
    • 注意,它其实是一个 React 组件:
      • 首字母大小
      • 返回 JSX
  • 第7行:将 App 组件作为默认导出
  • 第4行:它的返回值是一个 JSX
  • 注意,它其实是一个 React 组件:
    • 首字母大小
    • 返回 JSX
  • 首字母大小
  • 返回 JSX

运行和构建

# 运行
yarn dev

# 构建
yarn build

注意

使用 create-react-app 工具,可以在普通的 JS/TS 文件中(*.js/*.ts)使用 JSX 语法;但使用 vite 创建的 react 项目,只能在 *.jsx/*.tsx 文件中使用 JSX 语法。

本章源码

要查看完整内容,请先登录