一、介绍 React 路由和创建第一个路由
单页应用(SPA)已成为开发 web 应用的事实标准。许多 JavaScript 库和框架已经出现,帮助前端工程师开发 SPA。其中包括 React、Angular、Ember 和 Backbone 等。这些库或框架抽象本机 API,并提供可用于更快构建应用的服务和组件。水疗是提供流畅用户体验的绝佳选择;当用户遍历站点时,会触发 HTTP 请求,只更新页面的某些部分,而不是请求服务器处理整个页面。
React 是一个开源 JavaScript 库,可帮助您在 web 和移动应用中构建用户界面和视图层。它鼓励开发人员将视图层可视化为可在整个应用中重用的组件集合。大多数前端框架都包含一个路由包,当用户单击网站上提供的各种链接时,您可以使用该路由包更新页面的各个部分。前端框架中的路由侦听 URL 中的更改,并通过呈现相应的视图组件来保持应用的同步。例如,当用户访问'/dashboard'
时,页面将呈现各种仪表板组件,如图表和表格;当用户访问'/user'
时,页面将列出各种用户属性。在基于 React 的应用中,需要路由库,因为 React 不附带路由库。React 路由是一种完全使用 React 构建的流行路由库。该库包括各种组件,可用于在用户浏览应用时呈现视图。除了匹配 URL 和呈现视图组件外,React Router 还有几个功能可以帮助您轻松配置路由
本章讨论了以下主题:
- 简要介绍 React:本节向您介绍 React 中的一些核心概念,例如基于组件的体系结构、在 React 中创建组件,以及如何将数据提供给应用树中的子组件
- React 路由简介:在这里,我们首先使用
create-react-app
CLI 创建 React 应用,然后添加 React 路由库(即'react-router-dom'
包)作为依赖项 - 创建第一条路由:添加 React Router 作为依赖项后,使用
<BrowserRouter>
和<Route>
组件创建应用的第一条路由
简单看一下 React
React 是一个 JavaScript 库,它提供一组组件和服务,并使您能够构建用户界面。
以下是一段引用自reactjs.org
:
"React is a declarative, efficient, and flexible JavaScript library for building user interfaces."
该图书馆由 Facebook 开发和维护,并获得麻省理工学院的许可。它广泛用于在 Facebook 上构建各种应用,包括 Facebook web 和 Instagram web。
React 使您能够构建视图组件,这些组件在应用状态更改时更新。此处的状态可以指基础域数据,也可以反映用户在应用旅程中的位置。React 确保视图组件反映应用状态。
以下是 React 的一些重要功能:
- JSX:React 应用中的组件使用类似 XML/HTML 的语法(称为 JSX)来呈现视图元素。JSX 允许您在 JavaScript/React 代码中包含 HTML;在 React 组件的呈现函数中使用熟悉的 HTML 语法和属性,不需要学习新的模板语言。然后,预处理器(如 Babel)使用此 JSX 将 HTML 文本转换为 JavaScript 引擎可以理解的 JavaScript 对象。
- 单向数据绑定:React 应用被组织为一系列嵌套组件;一组不可变值作为 HTML 标记中的属性传递给组件的呈现器。组件不会修改从其父级接收的属性(或道具);相反,子组件将用户操作传递给其父组件,父组件通过更新组件的状态来修改这些属性。
- 虚拟 DOM:在 React 中,为每个 DOM 对象创建一个与真实 DOM 对象具有相同属性集的对应虚拟 DOM 对象。但是,当用户与页面交互时,虚拟 DOM 对象缺乏更新视图的能力。只要检测到状态发生变化,React 中的组件就会重新呈现视图元素,并且此重新呈现会更新虚拟 DOM 树。React 然后将此虚拟 DOM 树与更新之前创建的快照进行比较,以确定更改的 DOM 对象。最后,React 通过只更新那些已更改的 DOM 对象来修改真正的 DOM
React 中基于组件的体系结构
自 2013 年发布以来,React 重新定义了前端应用的构建方式。它引入了基于组件的体系结构的概念,本质上,它允许您可视化应用,就像它是由微小的、自我维持的视图组件组成的一样。这些视图组件是可重用的;也就是说,CommentBox
或Footer
等组件封装了必要的功能,可以跨站点中的页面使用。
此上下文中的页面本身就是由其他微小视图组件组成的视图组件,如下所示:
<Dashboard>
<Header>
<Brand />
</Header>
<SideNav>
<NavLink key=”1”>
<NavLink key=”2”>
</SideNav>
<ContentArea>
<Chart>
<Grid data="stockPriceList">
</ContentArea>
<Footer />
</Dashboard>
这里,<Dashboard>
是一个视图组件,它包含几个其他视图组件(Header
、SideNav
、ContentArea
和Footer
),而这些视图组件又由微小组件(Brand
、NavLink
、Chart
和Grid
组成。基于组件的体系结构鼓励您构建提供特定功能且不与其任何父组件或同级组件紧密耦合的组件。这些组件实现某些功能,并提供一个界面,通过该界面可以将它们包含在页面中。
在前面的示例中,<Grid>
组件将包括一些功能,如按行和列呈现数据,提供搜索功能,以及按升序或降序对列排序的选项。<Grid>
组件将实现上述所有功能,并提供一个可将其包含在页面中的接口。这里的接口将包括标签名(Grid
和一组属性(props
),它们接受来自其父组件的值。在这里,<Grid>
组件可以与后端系统接口并检索数据;但是,这会使组件紧密地绑定到给定的后端接口,因此无法使其可重用。理想情况下,视图组件将从其父组件接收数据并相应地采取行动:
<Grid data="stockPriceList" />
在这里,<Grid>
组件通过其data
道具接收包含股价信息的列表,并以表格格式呈现该信息。包含该<Grid>
组件的组件可以称为Container
组件,而Grid
可以称为子组件。
Container
组件也是View
组件;但是,它的责任包括为其子组件提供必要的数据以进行渲染。Container
组件可以启动对后端服务的 HTTP 调用,并接收呈现其子组件所需的数据。除此之外,Container
组件还负责在其视图区域中定位各个视图组件。
创建 React 组件
React 组件是通过扩展 React 提供的Component
类创建的,如下所示:
import React, { Component } from 'react';
import './button.css';
export class Button extends Component {
render() {
return (
<button className={this.props.type}>
{this.props.children}
</button>
);
}
}
在这里,Button
类扩展 React 的Component
类并重写render
方法。render
方法返回 JSX,页面加载时将在 DOM 上呈现。type
和children
属性在this.props
中提供。React 允许您通过道具将数据传递到其组件,并使用以下语法进行传递:
import React, { Component } from 'react';
import { Button } from './components/Button/button';
import './App.css';
export default class App extends Component {
render() {
return (
<div className="App">
<Button type="secondary">CANCEL</Button>
<Button type="primary">OK</Button>
</div>
);
}
}
在这里,我们将Button
组件包装在父组件App
中,以呈现两个按钮元素。Button
组件使用type
属性来设置CANCEL
和OK
按钮的类名(className
以及Button
标记中提到的文本。这可以使用children
属性进行引用。children
属性可以是纯文本或其他视图组件。子组件使用this.props
获取对其父组件提供的数据的引用。'this.props'
中的children
属性提供了对父组件标记之间包含的所有子元素的引用。如果在过去使用过角度,那么考虑前面的片段,类似于如何使用 AngularJS 中的 ToeT13q 或角的 Ty14 T14。
这里,<App>
组件包含<Button>
组件,可以称为容器组件,负责呈现页面上的按钮。
下一步是在 DOM 上呈现<App>
组件。<App>
组件作为根组件,即树中的根节点。应用中的每个组件都有<App>
组件作为其最顶层的父组件:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
ReactDOM.render(<App />, document.getElementById('root'));
此代码包含在导入React
和ReactDOM
库的index.js
中。ReactDOM
库有一个render
方法,该方法接受要呈现的组件作为其第一个参数,以及对必须呈现根组件的 DOM 节点的引用。
当应用运行时,<App>
组件内的内容被呈现:
React 路由简介
React Router 是使用 React 构建的 SPA 路由库。React 路由版本 4 是一个完整的重写版本,包含基于组件架构的 React 理念。
这来自 React 路由文档(https://reacttraining.com/react-router/ )
"React Router is a collection of navigational components that compose declaratively with your application. Whether you want to have bookmarkable URLs for your web app or a composable way to navigate in React Native, React Router works wherever React is rendering--so take your pick!"
React 路由可用于 React 应用的任何地方;也就是说,React Router 可以在浏览器中工作,也可以在 React native 的本机环境中工作。
该库分为三个包:
react-router
:DOM 和本机版本的通用核心组件react-router-dom
:用于浏览器和 web 应用的组件react-router-native
:用于使用 React native 构建的本机应用的组件
该库提供了各种组件,可用于向应用动态添加路由。React Router v4 中的动态路由允许您在用户完成应用旅程时指定应用路由。AngularJS 和 Express 等框架要求您预先指定路由,并且在应用引导时需要此路由信息。事实上,React Router 的早期版本遵循相同的范例,要求路由配置在前端可用。
除了在 React 应用中提供动态路由和流体导航外,该库还包括传统网站中提供的各种功能。这些措施包括:
- 在应用中前后导航、维护历史记录和恢复应用的状态
- 呈现 URL 时呈现适当的页面组件(深度链接)
- 将用户从一条路由重定向到另一条路由
- 支持在没有任何路由与 URL 匹配时呈现 404 页面
- 支持基于散列的路由和 HTML5 模式的漂亮 URL
It's a common misconception that React-Router is the official routing solution provided by Facebook. In reality, it's a third-party library and is licensed under MIT.
快速入门
让我们创建一个 React 应用,然后添加 React 路由作为依赖项。
要创建 React 应用,我们将使用create-react-app
CLI。create-react-app
CLI 使创建已经运行的应用变得更容易。CLI 创建了一个项目脚手架,以便您可以开始使用最新的 JavaScript 功能,还提供了为生产环境构建应用的脚本。有各种 React 和 React 路由启动器套件可用;然而,使用create-react-app
有助于演示如何将 React 路由添加到现有的裸体 React 应用中。
第一步是使用 NPM 全局安装create-react-app
,如下所示:
npm install -g create-react-app
CLI 要求node
版本大于等于 6,npm
版本大于 5.2.0。
一旦安装了 CLI,我们将使用create-react-app
命令创建一个新的应用,如下所示:
create-react-app react-router-demo-app
当create-react-app
完成软件包安装时,显示以下输出:
Inside that directory, you can run several commands:
npm start
Starts the development server.
npm run build
Bundles the app into static files for production.
npm test
Starts the test runner.
npm run eject
Removes this tool and copies build dependencies, configuration
files
and scripts into the app directory. If you do this, you can't
go back!
We suggest that you begin by typing:
cd react-router-demo-app
npm start
如果您使用了yarn
包管理器(https://yarnpkg.com/en/ ),前面代码段中的npm
命令将替换为yarn
。
react-router-demo-app
目录是在安装过程中创建的(如果它不存在)。在目录中,将创建以下项目结构:
/react-router-demo-app
|--node_modules
|--public
| |--favicon.ico
| |--index.html
| |--manifest.json
|--src
| |--App.css
| |--App.js
| |--App.test.js
| |--index.css
| |--index.js
| |--logo.svg
| |--registerServiceWorker.js
|--package-lock.json
|--package.json
|--README.md
CLI 安装了所有必要的依赖项,如 Babel,以将 ES6 代码传输到 ES5,从而使您能够利用最新的 JavaScript 功能。它还可以在 webpack 的帮助下创建一个构建管道配置。安装后,无需额外配置即可启动或构建应用。如前面的输出所述,您可以使用npm start
命令启动应用,并使用npm build
构建生产就绪的应用。
运行npm start
时,应用被编译,并将打开一个浏览器窗口,显示欢迎响应消息,如下所示:
在index.js
文件中,ReactDOM
引用用于呈现应用的根组件,如下所示:
ReactDOM.render(<App />, document.getElementById('root'));
<App>
组件标记应用启动时将呈现的树的开始。
添加 React 路由库
现在我们已经启动并运行了示例应用,让我们使用npm
将 React Router library 添加为一个依赖项:
npm install --save react-router-dom
此命令将下载并将react-router-dom
添加到/node_modules
目录中。package.json
文件现在将此作为依赖项包含:
"dependencies": {
"react": "^16.4.0",
"react-dom": "^16.4.0",
"react-router-dom": "^4.3.0",
"react-scripts": "1.1.4"
}
At the time of writing this book, version 4.3.0 of react-router-dom
was available. You can try the alpha and beta builds by mentioning react-router-dom@next
when including the library using npm
.
定义应用路由
react-router-dom
包包含一个<BrowserRouter>
组件,该组件在应用中添加路由之前用作包装器。要在 React 本机应用中使用 React 路由,请使用react-router-native
包。这将在后面的章节中详细讨论。<BrowserRouter>
组件是路由接口的一个实现,它利用 HTML5 的历史 API 使 UI 与 URL 路径保持同步。
第一步是用<BrowserRouter>
包装应用的根组件,如下所示:
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
将您的应用包装到<BrowserRouter>
中将为我们的<App>
组件创建一个历史实例,使其所有子组件都可以访问本机浏览器历史 API 中的道具。这允许组件与 URL 路径匹配,并呈现适当的页面组件。
History is a JavaScript library that lets you manage history stack navigation and helps in persisting state between sessions.
React Router 中的路由实际上并不是路由,而是基于与当前 URL 路径匹配的模式对组件进行条件呈现。要定义路由,我们需要两条信息:要匹配的 URL 路径和要呈现的组件。让我们创建两个组件,HomeComponent
和DashboardComponent
,分别在/home
和/dashboard
进行渲染。
在src/components/home/home.component.js
中:
import React from 'react';
export const HomeComponent = () => (
<div>
Inside Home route
</div>
);
在src/components/dashboard/dashboard.component.js
中:
import React from 'react';
export const DashboardComponent = () => (
<div className="dashboard">
Inside Dashboard route
</div>
);
import
语句是必需的,因为我们从前面的组件返回 JSX。
下一步是使用Route
组件定义路由(来自'react-router-dom'
。Route
组件接受多个道具,但在本例中,我们将使用path
和component
。
在App.js
中:
class App extends Component {
render() {
return (
<div className="container">
<Route
path="/home"
component={HomeComponent}
/>
<Route
path="/dashboard"
component={DashboardComponent}
/>
</div>
);
}
}
export default App;
这里,我们在<App>
组件的'render'
方法中定义路由。每个<Route>
组件都有一个path
道具,其中提到要匹配的 URL 路径;还有一个component
道具,其中提到路径匹配 URL 后要呈现的组件。
In the preceding example, the component was created without extending React's component class. If a component, created by extending React's component class, is provided as a value to the component
prop, then the component's lifecycle methods, componentWillMount
and componentWillUnmount
, are called every time that <Route>
renders the component.
当您运行应用(npm start
并访问localhost:3000/home
时,HomeComponent
被呈现并显示主页组件内部的消息。类似地,DashboardComponent
在您访问localhost:3000/dashboard
时呈现。
<BrowserRouter>
创建一个History
对象,该对象用于跟踪当前位置,并在站点发生更改时重新渲染该站点。<BrowserRouter>
通过 React 的上下文将History
对象提供给其子组件。没有<BrowserRouter>
作为其父项的Route
组件将无法工作。
此外,<BrowserRouter>
必须只有一个子元素。在下面的代码片段中,<BrowserRouter>
给出了两个子元素:
<BrowserRouter>
<Route
path="/home"
component={HomeComponent} />
<Route
path="/dashboard"
component={DashboardComponent} />
</BrowserRouter>
前面的代码将导致错误,例如可能只有一个子元素。要解决这个问题,您可以将这些路由移动到组件中并提供组件引用,或者将前面代码段中的<Route>
组件包装到另一个元素中,例如div
或React Fragment
。
A React fragment
is used to group a list of children without adding extra nodes to the DOM. A fragment is used when the component returns multiple elements.
React 路由库中除了BrowserRouter
之外,还有其他类型的路由:HashRouter
、MemoryRouter
和StaticRouter
。这些将在后面的章节中讨论。
总结
React 是一个用于构建用户界面的 JavaScript 库。与 Angular 和 Ember 等包含路由包的库不同,React 库不包含任何有助于路由的组件或服务。React Router 是一个路由库,可用于任何 React 应用(web 或本机)。React 路由版本 4 是对早期版本的完全重写,其所有组件都是用 React 编写的。该库包括用于 web 应用的包react-router-dom
;react-router-native
,用于使用 React native 构建的本机应用;以及react-router-dom
和react-router-native
都依赖的核心包react-router
create-react-app
CLI 用于快速构建 React 应用。它包括可用于生成开发和生产环境的构建的构建配置脚本。然后将react-router-dom
包作为依赖项添加到应用中。该包包括<BrowserRouter>
组件,该组件实现了History
接口。应用的根组件<App />
被包装在 React Router 的<BrowserRouter>
组件中,以使History
对象可用于应用树中的所有组件
为了创建我们的第一条路由,包含了<Route>
组件。它接受path
和component
作为道具,并在浏览器的 URL 与<Route>
路径匹配时呈现该组件
在第 2 章中配置路由-使用路由组件中的各种选项,详细讨论了<Route>
组件道具。此外,我们将查看渲染组件接收到的各种道具,并考虑如何使用这些道具来创建嵌套路由。
版权属于:月萌API www.moonapi.com,转载请注明出处