The content of the notes is reproduced from AcWing's Web Application Course handout, course link: AcWing Web Application Course .
CONTENTS
This section describes how to match pages and URLs one-to-one.
1. Web classification
Web pages can be divided into two broad categories:
- Static page: The data in the page is hard-coded, that is, the entire file is stored on the server. When the user accesses the URL, the server passes the page information to the front end intact.
- Dynamic page: The data in the page is filled dynamically, that is, the template of the page is stored on the server , and the data is stored in the database. When the user opens the page, the page will be dynamically spliced together. Nowadays, they are generally dynamic pages.
- Back-end rendering: Data is filled in at the back-end, that is, the splicing operation of template and data is performed on the server side. The client sends the URL to the server, and the server returns the spliced page.
- Front-end rendering: Data is filled in at the front-end, that is, the splicing operation of template and data is performed in the user's browser. When the page is opened for the first time , the client sends the URL to the server, and the server returns the templates of all pages . During rendering, it requests data from the server based on what data is currently needed; when the page is opened for the second time, JS is used to directly refresh the current page. page, does not necessarily send a request to the backend.
2.Route component
The Route component allows our front-end page to uniquely correspond to a URL, making the front-end rendering mode look the same as the back-end rendering mode.
We create a new project route-app
and open the project with VS Code:
create-react-app route-app
Configure the environment:
- VS Code installation plug-in:
Auto Import - ES6, TS, JSX, TSX
- Install the Route component (install it in the project root directory, restart VS Code after installation):
npm i react-router-dom
- Install Bootstrap:
npm i bootstrap
Route component introduction:
BrowserRouter
: All components that require routing must be wrapped inBrowserRouter
components;Link
: Jump to a link (but no request is sent to the backend),to
the attribute indicates the link to jump to;Routes
: Similar to the one in C++switch
, but only matches the first path, that is, looking at each path from front to backRoute
, judging whether the current link is equal toRoute
the link in , if so, renderingRoute
the component in , and the subsequent judgment will not continue;Route
: Route,path
the attribute represents the path, andelement
the attribute represents the content (component) routed to.
We first create the root component of our project App
, the navigation bar NavBar
, and the components of multiple sub-pages: Home
, Linux
, Django
, Web
, NotFound
.
NavBar
code show as below:
import React, {
Component } from 'react';
class NavBar extends Component {
state = {
}
render() {
return (
<nav className="navbar navbar-expand-lg bg-body-tertiary">
<div className="container-fluid">
<a className="navbar-brand" href="/">讲义</a>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<a className="nav-link active" aria-current="page" href="/">Home</a>
<a className="nav-link" href="/linux">Linux</a>
<a className="nav-link" href="/django">Django</a>
<a className="nav-link" href="/web">Web</a>
</div>
</div>
</div>
</nav>
);
}
}
export default NavBar;
App
code show as below:
import React, {
Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import NotFound from './notfound';
class App extends Component {
state = {
}
render() {
return (
<React.Fragment>
<NavBar />
</React.Fragment>
);
}
}
export default App;
Home
, Linux
, Django
, Web
, NotFound
the codes are similar, only one is shown:
import React, {
Component } from 'react';
class Home extends Component {
state = {
}
render() {
return (
<h1>Home</h1>
);
}
}
export default Home;
Now we render the page based on the URL. Note that this is still back-end rendering, and the page will be reloaded every time. We modify App
:
import React, {
Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import NotFound from './notfound';
import {
Routes, Route } from 'react-router-dom'
class App extends Component {
state = {
}
render() {
return (
<React.Fragment>
<NavBar />
<Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route
<Route path='/' element={
<Home />} /> // 如果链接为'/'就跳到Home组件
<Route path='/linux' element={
<Linux />} />
<Route path='/django' element={
<Django />} />
<Route path='/web' element={
<Web />} />
</Routes>
</React.Fragment>
);
}
}
export default App;
Now we Link
replace NavBar
the link tag in a
with so that it becomes front-end rendering:
import React, {
Component } from 'react';
import {
Link } from 'react-router-dom'
class NavBar extends Component {
state = {
}
render() {
return (
<nav className="navbar navbar-expand-lg bg-body-tertiary">
<div className="container-fluid">
<Link className="navbar-brand" to="/">讲义</Link>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<Link className="nav-link" aria-current="page" to="/">Home</Link>
<Link className="nav-link" to="/linux">Linux</Link>
<Link className="nav-link" to="/django">Django</Link>
<Link className="nav-link" to="/web">Web</Link>
</div>
</div>
</div>
</nav>
);
}
}
export default NavBar;
3. Pass parameters in the URL
When the website has a large number of pages, it is certainly impossible for us to write so many Route
.
Suppose we now have several Web lecture notes, iiThe routing link of article i/web/content/i
is: :
import React, {
Component } from 'react';
import {
Link } from 'react-router-dom'
class Web extends Component {
state = {
webs: [
{
id: 1, title: 'HTML基础标签'},
{
id: 2, title: 'CSS'},
{
id: 3, title: 'JavaScript'},
{
id: 4, title: '中期项目-拳皇'},
{
id: 5, title: 'React'},
]
}
render() {
return (
<React.Fragment>
<h1>Web</h1>
<hr />
<div>
{
this.state.webs.map(web => (
<div key={
web.id}>
<Link to={
`/web/content/${
web.id}`}>{
web.id + '.' + web.title}</Link>
</div>
))}
</div>
</React.Fragment>
);
}
}
export default Web;
Let’s first implement the components of the handout content WebContent
:
import React, {
Component } from 'react';
class WebContent extends Component {
state = {
}
render() {
return (
<h1>Web Content</h1>
);
}
}
export default WebContent;
Then App
write the route in (we can’t write multiple <Route path='/web/content/i' element={<WebContent />} />
, but use :xxx
):
import React, {
Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import WebContent from './webcontent';
import NotFound from './notfound';
import {
Routes, Route } from 'react-router-dom'
class App extends Component {
state = {
}
render() {
return (
<React.Fragment>
<NavBar />
<div className='container'>
<Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route
<Route path='/' element={
<Home />} /> // 如果链接为'/'就跳到Home组件
<Route path='/linux' element={
<Linux />} />
<Route path='/django' element={
<Django />} />
<Route path='/web' element={
<Web />} />
<Route path='/web/content/:chapter' element={
<WebContent />} />
</Routes>
</div>
</React.Fragment>
);
}
}
export default App;
Now how do we WebContent
get :chapter
the parameters in ? Let’s first look at how the function component obtains parameters. You can directly use useParams
the function to obtain parameters:
import React from 'react';
import {
useParams } from 'react-router-dom';
const WebContent = () => {
console.log(useParams())
return (
<h1>Web Content - {
useParams().chapter}</h1>
);
}
export default WebContent;
If it is a class component, you need to first set a layer of function components, and then pass useParams
the function to yourself as a parameter:
import React, {
Component } from 'react';
import {
useParams } from 'react-router-dom';
class WebContent extends Component {
state = {
}
render() {
console.log(this.props.params)
return (
<h1>Web Content - {
this.props.params.chapter}</h1>
);
}
}
export default (props) => (
<WebContent
{
...props} // 先把函数组件里面的属性展开
params={
useParams()}
/>
);
4. Search Params transfer parameters
If the website link format is: /web/content?chapter=3
, such a link can also obtain parameters.
Let's first change Web
the link form in :
import React, {
Component } from 'react';
import {
Link } from 'react-router-dom'
class Web extends Component {
state = {
webs: [
...
]
}
render() {
return (
<React.Fragment>
<h1>Web</h1>
<hr />
<div>
{
this.state.webs.map(web => (
<div key={
web.id}>
<Link to={
`/web/content?chapter=${
web.id}`}>{
web.id + '.' + web.title}</Link>
</div>
))}
</div>
</React.Fragment>
);
}
}
export default Web;
Then WebContent
get the parameters of the link in :
import React, {
Component } from 'react';
import {
useSearchParams } from 'react-router-dom';
import {
Link } from 'react-router-dom'
class WebContent extends Component {
state = {
searchParams: this.props.params[0], // 用于获取某一个参数
setSearchParams: this.props.params[1], // 用于设置链接里的参数,重新渲染页面
};
render() {
console.log(this.state.searchParams.get('chapter'))
return (
<React.Fragment>
<h1>Web Content - {
this.state.searchParams.get('chapter')}</h1>
<hr />
<div>讲义内容</div>
<hr />
<Link to='/web'>返回上一级</Link>
</React.Fragment>
);
}
}
export default (props) => (
<WebContent
{
...props} // 先把函数组件里面的属性展开
params={
useSearchParams()}
/>
);
Function components are written as follows:
import React from 'react';
import {
useSearchParams } from 'react-router-dom';
import {
Link } from 'react-router-dom'
const WebContent = () => {
let [searchParams, setSearchParams] = useSearchParams();
console.log(searchParams.get('chapter'));
return (
<React.Fragment>
<h1>Web Content - {
searchParams.get('chapter')}</h1>
<hr />
<div>讲义内容</div>
<hr />
<Link to='/web'>返回上一级</Link>
</React.Fragment>
);
}
export default WebContent;
5. Redirect
When a link that does not exist should be redirected 404 Not Found
, we first define this route: <Route path='/404' element={<NotFound />} />
.
Using Navigate
the component can redirect, we can use wildcards *
to match all the remaining paths and then redirect them to /404
the page:
import React, {
Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import WebContent from './webcontent';
import NotFound from './notfound';
import {
Routes, Route, Navigate } from 'react-router-dom'
class App extends Component {
state = {
}
render() {
return (
<React.Fragment>
<NavBar />
<div className='container'>
<Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route
<Route path='/' element={
<Home />} /> // 如果链接为'/'就跳到Home组件
<Route path='/linux' element={
<Linux />} />
<Route path='/django' element={
<Django />} />
<Route path='/web' element={
<Web />} />
<Route path='/web/content' element={
<WebContent />} />
<Route path='/404' element={
<NotFound />} />
<Route path='*' element={
<Navigate replace to='/404' />} />
</Routes>
</div>
</React.Fragment>
);
}
}
export default App;
6. Nested routing
Assuming Linux
there are two submodules Homework
and in the component Terminal
, we can App
create nested routes in :
import React, {
Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import WebContent from './webcontent';
import NotFound from './notfound';
import {
Routes, Route, Navigate } from 'react-router-dom'
class App extends Component {
state = {
}
render() {
return (
<React.Fragment>
<NavBar />
<div className='container'>
<Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route
<Route path='/' element={
<Home />} /> // 如果链接为'/'就跳到Home组件
<Route path='/linux' element={
<Linux />}>
<Route path='homework' element={
<h4>Homework</h4>} />
<Route path='terminal' element={
<h4>Terminal</h4>} />
</Route>
<Route path='/django' element={
<Django />} />
<Route path='/web' element={
<Web />} />
<Route path='/web/content' element={
<WebContent />} />
<Route path='/404' element={
<NotFound />} />
<Route path='*' element={
<Navigate replace to='/404' />} />
</Routes>
</div>
</React.Fragment>
);
}
}
export default App;
But now /linux/homework
when the web page is executed, the content of the sub-route will not be rendered. We need to add <Outlet />
the component to the parent component to fill in the content of the sub-component:
import React, {
Component } from 'react';
import {
Link, Outlet } from 'react-router-dom'
class Linux extends Component {
state = {
}
render() {
return (
<React.Fragment>
<h1>Linux</h1>
<hr />
<ul className="nav justify-content-center">
<li className="nav-item">
<Link className="nav-link" to="/linux/homework">Homework</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/linux/terminal">Terminal</Link>
</li>
</ul>
<hr />
<Outlet />
</React.Fragment>
);
}
}
export default Linux;