1、安装
React 从一开始就被设计为可以被渐进地采用,你可以根据需要或多或少地试用 React。无论你只是想体验一下 React,并为 HTML 页面添加一些交互性,还是创建一个复杂的 React
In this chapter
如何将 React 添加到 HTML 页面中
如何新建一个独立的 React 项目
如何设置编辑器
如何安装 React 开发者工具
试用 React
无需安装任何东西就可以试用 React。请试着修改以下代码!
function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
}
export default function App() {
return <Greeting name="world" />
}
我们在所有文档中使用代码沙盒(sandbox)作为教学的辅助工具。代码沙盒可以帮助你熟悉 React 的工作原理,并帮助你考察 React 是否适用。除了 React 文档外,还有许多支持 React 的第三方在线代码沙盒,例如:CodeSandbox 、Stackblitz 或 CodePen。
在本地试用 React,在页面中添加 React
要在本地计算机上试用 React 的话,打开一个html网页。然后在编辑中打开并编辑,在浏览器中查看效果。如果你手头已经有一个能运行的网站了,只想利用 React 添加一点儿功能的话,看后续介绍
创建一个 React 项目
如果你已经准备利用 React 创建一个独立的项目
,那么你可以设置一个最小的工具链,让开发体验更愉快。你还可以使用现成的框架,直接开箱即用。
下一步
从哪里开始学习取决于你喜欢什么样的学习方式、需要完成的目标以及你接下来的打算!为什么不从阅读 (我们的入门教程)开始呢?或者你可以跳转到 描述 UI
章节拿更多示例练练手并一步步地学习每个知识点。记住,没有那种学习 React 的路径是错误的!
1.1、创建一个 React 新项目
如果你正在学习 React 或者考虑将其应用到现有的项目中,你可以利用script 标签将 React添加到任何 HTML 页面,来快速开启学习之旅。如果你的项目需要许多组件和许多文件,那就需要考虑以下方式了!
1.2、选择你自己的冒险方式
React 是一个工具库,帮你以组件的方式拆解并组织 UI 代码。React 不负责路由(routing)或数据管理。对于这些功能,你需要使用第三方工具库或实现你自己的解决方案。这意味着创建一个新的 React 项目有多种方式可以选择:使用 最小设置的工具链, 根据需要为项目添加功能。使用 功能完备的框架,常用功能都已内置。无论你是刚入门,想要构建一个大项目,还是想要建立自己的工具链,本指南都能为你指明道路。
1.3、React 工具链入门
如果你是刚刚开始接触 React,我们建议你使用 create React App ,这是尝试 React 功能的最流行的方式,也是构建新的单页客户端应用的最好方法。Create React App 是一个专为 React 配置的功能齐备的工具链。工具链有助于:
创建大量的文件和组件
使用来自 npm 的第三方工具库
及早检测到常见错误
开发时能实时编辑 CSS 和 JS
针对生产环境优化输出的文件
你仅需一条命令就可以在终端(命令行)中利用 Create React App 创建一个新项目!(前提是确保安装了Node.js !)
npx create-react-app my-app
现在就可以通过以下命令运行你的应用程序了:
cd my-app
npm start
Create React App 并不处理后端逻辑或数据库操作,它只是创建了一个针对前端的构建管道。这意味着你可以为其对接任何后端。但是,如果你寻找的是对类似路由(routing)以及服务器端业务逻辑功能的支持的话,请接着往下看!
1.4、同时使用 React 和框架
如果你希望创建一个更大的、可用于生产环境的项目的话,
Next.js 是一个非常好的起点。Next.js 是一个流行的、基于 React 构建的轻量级框架,用于构建静态和服务器端渲染的应用程序。该框架自带了路由(routing)、样式表( styling)和服务器端渲染(server-side rendering)等功能,可以让你的项目快速开始并运行起来。
请查看 Next.js 的官方指导:使用 Next.js 构建项目
1.5、其他选项
Gatsby 能帮你基于 React 和 GraphQL 生成静态网站。
Razzle是一个支持服务器端渲染(server-rendering)的框架,无需任何配置,但比 Next.js 提供了更多的灵活性。
1.6、自定义工具链
你可能更喜欢创建并配置自己的工具链。一个 JavaScript 构建工具链通常包含以下部分:
一个 软件包管理器---用于安装、更新和管理第三方软件包。
Yarn 和
npm 就是两个比较流行的软件包管理器。
一个 打包工具(bundler)---将您编写的模块化代码打成小包以优化加载时间。Webpack
、Snowpack、Parcel 就是几个比较流行的打包工具。
一个 编译器---将你使用新语法编写的 JavaScript 代码转换成能被老版本的浏览器执行的代码。Babel 就是这类工具中的一个代表。
在较大的项目中,你可能还需要一个工具来管理单一仓库中的多个软件包。Nx
就是此类工具中的一个代表。
如果你喜欢葱头开始创建自己的 JavaScript 工具链的话,请 查看这份指南
来了解如何自行实现 Create React App 中的功能。
2、为网站添加 React
React 从一开始就被设计为支持渐进式采用,你可以根据需要或多或少地使用 React。无论是微前端(micro-frontends)、现有系统,还是只是尝试一下 React,都可以通过添加几行代码就能为页面添加交互式的 React 组件,并且无需使用构建工具!
2.1、第一步:在页面中添加一个 HTML 元素
在要编辑的 HTML 页面中添加一个 HTML 元素,例如带有唯一 id
属性的空的 <div>
标签,该标签用于 React 定位内容显示的位置。
你可以在 <body>
标签内的任何位置放置一个类似 <div>
的"容器"元素。React 将把该 HTML 元素内的任何内容替换掉,因此一个空标签即可。你可以根据需要在页面上放置任意多个类似的 HTML 元素。
<!-- ... existing HTML ... -->
<div id="component-goes-here"></div>
<!-- ... existing HTML ... -->
2.2、第二部:添加 script 标签
在 HTML 页面中,将以下三个文件通过 <script>
标签添加到 </body>
标签前:react.development.js 加载 React 核心代码 react-dom.development.js 让 React 渲染 HTML 元素到 DOM
中。
like_button.js 这将是你在第三步中编写组件的地方!部署到生产环境时,将 "development.js" 文件替换为 "production.min.js" 文件。
<!-- end of the page -->
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="like_button.js"></script>
</body>
2.3、React without JSX
最初引入 JSX 是为了让使用 React 编写组件的感觉就像写 HTML 一样。从那时起,改语法变得流行起来。但是,在某些情况下,你可能不想使用或无法使用 JSX。那么你有两个选择:使用类似htm
之类的 JSX 替代方案,htm 不需要编译器,而是使用 JavaScript 内置的标记模板(Tagged Templates)语法。
使用 React.createElement()
函数,该函数具有特殊结构,后面有详解。
通过使用 JSX,你可以像这样编写组件:
function Hello(props) {
return <div>Hello {props.toWhat}</div>;
}
ReactDOM.render(<Hello toWhat="World" />, document.getElementById('root'));
而使用 React.createElement()
函数的化,你需要像这样编码:
function Hello(props) {
return React.createElement('div', null, `Hello ${props.toWhat}`);
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
该函数接受三个参数: React.createElement(component, props, children)
。以下解释器工作原理:
一个 component 参数,可以实一个代表 HTML 元素的字符串,也可以是一个函数形式的组件
一个对象,可以是任何 你想传入的 props
一个对象,可以是任何 子 组件,例如文本字符串
如果你厌倦了输入 React.createElement()
,一个常规的办法是为其赋予一个速记符:
const e = React.createElement;
ReactDOM.render(e('div', null, 'Hello World'), document.getElementById('root'));
如果将此速记符来代替 React.createElement()
,就能在不使用 JSX 的情况下达成同样的便利。
3、设置编辑器
一个正确配置的编辑器能够让读代码更清晰、写代码更快。它甚至可以帮你在写代码时捕获 bug!如果这是你第一次设置编辑器,或者你希望调整编辑器,以下是我们的一些建议。
3.1、选择你的编辑器
VS Code 是如今最流行的编辑器之一。它拥有一个庞大的插件市场,并集成了 GitHub 等流行的服务。下面列出的功能大部分可以作为插件添加到 VS Code 中,插件让 VS Code 高度可配置!
React 社区中其它常用的编辑器包括:
WebStorm
---专为 JavaScript 设计的集成开发环境。Sublime Text
---支持 JSX 和 TypeScript,内置了语法高亮和自动代码补全功能。Vim
---一个高度可配置的文本编辑器,能够高效地创建和修改任何类型的文本。它作为 "vi" 命令存在于大多数 UNIX 系统和 Apple OS X 中。
3.2、推荐功能
某些编辑器内置了这些功能,但其它编辑器可能需要安装插件。请查看你所选择的编辑器是支持以下功能!
3.3、代码过滤(Linting)
代码过滤的作用是在你书写代码时发现代码中的错误,并帮助你今早修复错误。
ESLint是一个流行的、开源的 JavaScript 过滤器。
安装 ESLint 并使用 React 的推荐配置 (请确保 Node 已安装! )
利用官方插件将 ESLint 集成到 VSCode 中
3.4、格式化
与其他贡献者共享代码时,最不想做的事情就是讨论用制表符(tabs)还是空格(spaces)!幸好,有Prettier来重新清理代码使其符合预定义的规则。运行 Prettier,所有的制表符(tabs)都将转换为空格(spaces),缩进、引号等也将全部根据配置被修改。理想的设置是当你保存文件时,Prettier 就会运行并帮你完成这些修改。
你可以按如下步骤安装 Prettier extension in VSCode:
启动 VS Code
按快捷键(
CTRL/CMD + P
)粘贴
ext install esbenp.prettier-vscode
按回车键
保存文件时执行格式化,理想情况下,应该是在你每次保存文件时格式化代码。VS Code 已支持此设置!
在 VS Code 中,按
CTRL/CMD + SHIFT + P
。输入 "settings"
按回车键
在搜索栏中,输入 "format on save"
确保勾选了 "format on save" 选项!
Prettier 有时会与其它代码过滤其产生冲突。但是通常都会有办法让它们很好地配合工作。例如,如果需要同时使用 Prettier 和 ESLint,则可以使用 eslint-prettier 插件并通过 ESLint 规则来运行 prettier。
4、React 开发者工具
通过 React 开发者工具(React Developer Tools)可以检查 React components 、编辑 props
和 state,以及定位性能问题。
4.1、浏览器扩展
对使用 React 构建的网站进行调试的最简单方法就是安装并使用 React 开发者工具的浏览器扩展插件。该插件支持几种常简的浏览器:
为 Chrome 浏览器安装扩展插件
为 Firefox 浏览器安装扩展插件
为 Edge 浏览器安装扩展插件、
现在,如果你访问 基于 React 构建的网站 时,你将看到 Components 和 Profiler 面板。
4.2、Safari 和其它浏览器
对于其它浏览器(例如 Safari),请安装react-devtools 这一 npm 软件包:
# Yarn
yarn global add react-devtools
# Npm
npm install -g react-devtools
然后从终端(命令行)中开启开发者工具:
react-devtools
然后,通过在网站的 <head>
标签内添加以下 <script>
标签来连接网站:
4.3、移动端(React Native)
React 开发者工具也可用于检查基于React Native
构建的应用程序。将 React 开发者工具安装到全局环境中是最简单的方式:
# Yarn
yarn global add react-devtools
# Npm
npm install -g react-devtools
接下来打开终端(命令行)就可以使用开发者工具了。
react-devtools
该工具就可以连接到任何运行在本地机器上的 React Native 应用程序了。如果开发者工具经过几秒后仍无法连接,请尝试重启应用程序。
5、快速入门
欢迎访问 React 文档!本页将向您介绍 80% 的 React 概念,这些概念将是您日常开发中经常用到的。
You will learn
如何创建并嵌套组件
How to add markup and styles
如何展示数据
How to render conditions and lists
如何响应事件并更新屏幕显示
如何在组件间共享数据
创建并嵌套组件
React 应用程序是由组件(component)组成的。组件是 UI(用户界面)的组成部分,拥有自己的逻辑和外观。一个组件可以小到一个按钮,大到整个页面。
React 组件就是 JavaScript 函数(function),此类函数返回由标签语言编写的用户界面:
function MyButton() {
return (
<button>Click me</button>
);
}
现在,你已经声明了 MyButton
组件,接下来就可以将其嵌入到其它组件中了:
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}
请注意,<MyButton />
标签以大写字母开头,这样就能便于识别这个是一个 React 组件。React 组件的名称必须始终以大写字母开头,而 HTML 标签必须全部为小写字母。
看看成果:
function MyButton() {
return (
<button>
Click me
</button>
);
}
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}
export default
关键字在文件中标明了主要组件。
编写 JSX 语法的标签
你在前面看到的标记语言(markup syntax)称为 JSX。JSX 不是必须要用的,但是因为使用方便,所以大多数 React 项目都使用 JSX。所有 我们推荐的用于本地开发的工具
都自带对 JSX 的支持。
JSX 的语法比 HTML 更严格。类似 <br />
这样的标签是必须要关闭的。并且,组件也不能返回多个并列最高层级的 JSX 标签,你必须为所有最高层级的标签添加一个共同的父标签,例如使用 <div>...</div>
或 <>...</>
作为父标签:
function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}
如果你需要将大量 HTML 代码移植到 JSX 语法,可以使用这个 在线转换器。添加样式,在 React 中,通过 className
这个属性来指定 CSS 类。它和 HTML 的 class 属性的功能是一样的:
<img className="avatar" />
然后在一个单独的 CSS 文件中为其编写 CSS 样式:
/* In your CSS */
.avatar {
border-radius: 50%;
}
React 没有规定如何添加 CSS 文件。最简单的方式是添加一个 <link> 标签到页面的 HTML 代码中。如果你使用了构建工具或框架,请查阅其相关文档,以便了解如何将 CSS 文件添加到你的项目中。
5.1、React 编程思想
React 可以改变你对所看到的设计以及所构建的应用程序的看法。以前你看到的是一片森林,使用 React 后,你将欣赏到每一棵树。React 简化了你对设计系统(design system)和 UI 状态的看法。在本教程中,我们将带领你使用 React 构建一个可搜索的数据表产品,并领略整个思考的过程。
从原型开始
假设你已经拥有了一个 JSON API 以及一个来自设计师的原型设计。JSON API 返回的数据如下所示:
[
{ category: "Fruits", price: "$1", stocked: true, name: "Apple" },
{ category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit" },
{ category: "Fruits", price: "$2", stocked: false, name: "Passionfruit" },
{ category: "Vegetables", price: "$2", stocked: true, name: "Spinach" },
{ category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin" },
{ category: "Vegetables", price: "$1", stocked: true, name: "Peas" }
]
原型设计如下:
用 React 实现 UI 的话,通常遵循相同的五个步骤。
5.2、第一步:将 UI 分解为组件结构
首先,在原型图中的每个组件及其子组件周围画一个框,并为他们命名。如果你有设计师搭档的话,他们可能已经在设计工具中为这些组件命名了。请与他们确认!
根据你的背景不同,你可以考虑采用不同的方式将原型设计拆分为不同的组件:
编程---使用相同的技术来决定是否需要创建新函数或对象。其中一个方法是 单一责任原则(single responsibility principle),也就是说,一个组件在理理想情况下只负责一件事情。如果变得臃肿了,则应将其分解为更小的子组件。
CSS---考虑类选择器(class selector)的用途。(但是,组件的粒度要小一些。)。
设计---考虑如何阻止设计中所用的图层(layer)。
如果 JSON 的结构良好,你通常会发现它能很自然地映射到 UI 的组件结构上。这是因为 UI 和数据模型通常具有相同的信息结构,即相同的模型(shape)。将 UI 分成多个组件,每个组件将与数据模型的一部分相匹配。
下图中可以看到有五个组件:
注意看 ProductTable
(即紫色部分),你会发现表头(包含 "Name" 和 "Price" 字样)并非是独立组件。这其实是一个偏好的问题,你可以选择将其独立成组件或作 ProductTable
组件的组成部分。在本例中,表头是 ProductTable
的组成部分,因为它出现在 ProductTable
的列表中。但是,如果此表头变得复杂了(例如需要添加排序功能),则更适合将其提取为 ProductTableHeader
组件。
既然你已经在原型图中标识了组件,那么就将它们排列成一个层级结构吧。在原型图中如果一个组件出现在另一个组件中,那么就应该作为子组件显示在层级结构中:
FilterableProductTable
SearchBar
ProductTable
ProductCategoryRow
ProductRow
5.3、第二部:基于 React 构建静态版本
现在,你已经梳理了组件的层次结构,是时候开始实现这个应用程序了。最直接的方法是构建一个利用数据模型渲染 UI 的版本,此时无需添加任何交互功能。先构建静态版本然后再添加交互功能,通常是一条便捷的路径。构建静态版本需要大量的码字,但无需太多思考;而添加交互功能则需要大量的思考,码字反而不多。
要构建一个渲染数据模型的静态版本应用程序,你需要在重用其他组件的基础上构建新 组件(components)
并通过 props
传递数据。props 是将数据从父组件传递到子组件的一种方式。(如果你对于 state
的概念有了解的话,请不要使用 state(状态) 来构建这个静态版本的应用程序,state 仅用于交互,也就是随时间而变化的数据。由于这里要构建的是静态版本的应用程序,因此不要用 state。)
你可以按照"自上而下"(即,从较高层级的组件,例如 FilterableProductTable
,开始构建)或"自下而上"(即,从较低层级的组件,例如 ProductRow
,开始构建)的顺序构建所有组件。在比较简单的项目中,自上而下的方式通常共容易;而在较大的项目中,自下而上的方式更容易。
import { useState } from 'react';
function FilterableProductTable({ products }) {
const [filterText, setFilterText] = useState('');
const [inStockOnly, setInStockOnly] = useState(false);
return (
<div>
<SearchBar
filterText={filterText}
inStockOnly={inStockOnly}
onFilterTextChange={setFilterText}
onInStockOnlyChange={setInStockOnly} />
<ProductTable
products={products}
filterText={filterText}
inStockOnly={inStockOnly} />
</div>
);
}
function ProductCategoryRow({ category }) {
return (
<tr>
<th colSpan="2">
{category}
</th>
</tr>
);
}
function ProductRow({ product }) {
const name = product.stocked ? product.name :
<span style={{ color: 'red' }}>
{product.name}
</span>;
return (
<tr>
<td>{name}</td>
<td>{product.price}</td>
</tr>
);
}
function ProductTable({ products, filterText, inStockOnly }) {
const rows = [];
let lastCategory = null;
products.forEach((product) => {
if (
product.name.toLowerCase().indexOf(
filterText.toLowerCase()
) === -1
) {
return;
}
if (inStockOnly && !product.stocked) {
return;
}
if (product.category !== lastCategory) {
rows.push(
<ProductCategoryRow
category={product.category}
key={product.category} />
);
}
rows.push(
<ProductRow
product={product}
key={product.name} />
);
lastCategory = product.category;
});
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
);
}
function SearchBar({
filterText,
inStockOnly,
onFilterTextChange,
onInStockOnlyChange
}) {
return (
<form>
<input
type="text"
value={filterText} placeholder="Search..."
onChange={(e) => onFilterTextChange(e.target.value)} />
<label>
<input
type="checkbox"
checked={inStockOnly}
onChange={(e) => onInStockOnlyChange(e.target.checked)} />
{' '}
Only show products in stock
</label>
</form>
);
}
const PRODUCTS = [
{category: "Fruits", price: "$1", stocked: true, name: "Apple"},
{category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"},
{category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"},
{category: "Vegetables", price: "$2", stocked: true, name: "Spinach"},
{category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"},
{category: "Vegetables", price: "$1", stocked: true, name: "Peas"}
];
export default function App() {
return <FilterableProductTable products={PRODUCTS} />;
}