其他章節請看:
react 路由
本篇首先講解路由原理,接著以一個基礎路由示例為起點講述路由最基礎的知識,然後講解巢狀路由、路由傳參,最後講解路由元件和一般元件的區別,以及程式設計式導航。
Tip:我們要接手的 react 專案是:spug_web。
什麼是路由
路由就是根據不同的 url(網址) 返回不同的頁面(資料)。如果這個工作在後端做(或者說由後端程式設計師做),就是後端路由;在前端做就是前端路由。
平時總說的 SPA(單頁面應用)就是前後端分離的基礎上,再加一層前端路由。
react 路由原理
下面通過一個js 庫(history)來演示一下路由的原理:
<body>
請在瀏覽器控制檯下體驗!
<!-- https://github.com/remix-run/history/blob/dev/docs/installation.md -->
<script src="https://unpkg.com/history/umd/history.production.min.js"></script>
<script>
let myHistory = window.HistoryLibrary.createBrowserHistory()
let unlisten = myHistory.listen(({ location, action }) => {
console.log(action, location.pathname)
});
</script>
</body>
訪問頁面,瀏覽器 url 為 http://127.0.0.1:5500/public/test.html
Tip:筆者在 vscode 中安裝 “open in browser” 外掛,直接右鍵選擇 “Open with Live Server” 即可。
開啟控制檯進行測試:
> myHistory.push('/home')
PUSH /home
url 變為:http://127.0.0.1:5500/home
> myHistory.push('/about')
PUSH /about
url 變成:http://127.0.0.1:5500/about
> myHistory.back()
POP /home
url 變成:http://127.0.0.1:5500/home
> myHistory.replace('about')
REPLACE /about
url 變成:http://127.0.0.1:5500/about
> myHistory.back()
POP /public/test.html
url 變成:http://127.0.0.1:5500/public/test.html
這個流程其實就是 react 路由的基礎。
hash模式:
<script>
let hashHistory = window.HistoryLibrary.createHashHistory()
hashHistory.listen(({ location, action }) => {
console.log(action, location.pathname)
});
</script>
> hashHistory.push('/home')
PUSH /home
url 變為:http://127.0.0.1:5500/public/test.html#/home
Version 5 is used in React Router version 6 —— history
Tip:react router 用到了這個包,另外這個包的作者和 react-router
、react-router-dom
是同一人。
路由模式
react 中有三種模式,本篇主要研究 history 和 hash 兩種模式。
官網-history:
- “browser history” - 在特定 DOM 上的實現,使用於支援 HTML5 history API 的 web 瀏覽器中
- “hash history” - 在特定 DOM 上的實現,使用於舊版本的 web 瀏覽器中
- “memory history” - 在記憶體中的 history 實現,使用於測試或者非 DOM 環境中,例如 React Native
環境準備
筆者使用的環境是 react 腳手架建立的專案。
Tip:詳細介紹請看 react 腳手架建立專案
開啟 react-router 官網。
Tip:react 有三個版本,我們學習 web 版本 5
。印記中文(深入挖掘國外前端新領域,為中國 Web 前端開發...)有 react-router 中文。
基礎使用
安裝 react 路由依賴包:
react-cli-demo> npm i react-router-dom@5
added 13 packages, and audited 1421 packages in 6s
169 packages are looking for funding
run `npm fund` for details
6 moderate severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
注:版本是5,倘若是版本 6,下面的程式碼執行會報錯。
將 App.js 替換成下面程式碼:
// src/App.js
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
</Router>
);
}
// Home 元件
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
// About 元件
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
// Dashboard 元件
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
</div>
);
}
重啟伺服器,頁面顯示:
· Home
· About
· Dashboard
________________________________
Home
注:本篇為了演示,所以將多個元件都放在一個檔案中。
整個頁面分上下兩部分,上面是導航區
,下面是內容區
。
倘若點選導航“About”,內容區顯示 About,瀏覽器 url 也會變化:
http://localhost:3000/
變成
http://localhost:3000/about
當我們點選 <Link to="/about">About</Link>
,則會匹配上 <Route path="/about">
,於是 <About />
元件顯示。
Tip:Link
、exact
、<Switch>
、<Router>
的作用?請接著看。
Link 和 NavLink
<Link to="/about/a">About</Link>
會被渲染成 <a href="/about">About</a>
,即使點選 About 導航,渲染的內容依舊不變。
一個特殊版本的 Link,當它與當前 URL 匹配時,為其渲染元素新增樣式屬性 —— 官網-<NavLink>
將 About 導航改成 NavLink
:
<NavLink to="/about">About</NavLink>
初始時(即未選中)依舊渲染成 <a href="/about">About</a>
,但點選 About 導航後,渲染內容變成:
<a href="/about" aria-current="page" class="active">About</a>
所以我們可以給 .active
增加選中效果。
如果要修改預設選中時的 active
類名,可以使用 activeClassName
屬性。就像這樣:
<NavLink to="/about" activeClassName="z-selected">About</NavLink>
封裝 NavLink
- 版本1
function MyNavLink(props) {
return <NavLink to={props.to} activeClassName="z-selected">{props.children}</NavLink>
}
使用:
<MyNavLink to="/about" children="About" />
- 升級版
function MyNavLink(props) {
return <NavLink {...props} activeClassName="z-selected" />
}
當 React 元素為使用者自定義元件時,它會將 JSX 所接收的屬性(attributes)以及子元件(children)轉換為單個物件傳遞給元件,這個物件被稱之為 “props” —— react 官網
Router
使用 HTML5 歷史 API 記錄( pushState,replaceState 和 popstate 事件)的 <Router>
使您的UI與URL保持同步 —— 官網-BrowserRouter
假如將 BasicExample 元件中的 <Router>
刪除,瀏覽器控制檯將報錯如下:
Uncaught Error: Invariant failed: You should not use <Link> outside a <Router>
未捕獲的錯誤:不變式失敗:您不應該在 <Router> 之外使用 <Link>
倘若將 <Switch>
外邊的 <Router>
刪除,瀏覽器控制檯將報錯如下:
Uncaught Error: Invariant failed: You should not use <Switch> outside a <Router>
未捕獲的錯誤:不變數失敗:您不應該在 <Router> 之外使用 <Switch>
倘若將 <Route>
(<Switch>
在這裡可以刪除) 外邊的 <Router>
刪除,瀏覽器控制檯將報錯如下:
Uncaught Error: Invariant failed: You should not use <Route> outside a <Router>
未捕獲的錯誤:不變式失敗:您不應在 <Router> 之外使用 <Route>
倘若我們在 BasicExample 元件中使用兩個 <Router>
會發生什麼?
export default function BasicExample() {
return (
<div>
<Router>
<ul>
<li>
<Link to="/">Home</Link>
</li>
...
</ul>
</Router>
<hr />
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
...
</Switch>
</Router>
</div>
);
}
瀏覽器沒有任何報錯,點選導航“About”,url正常變化,但內容區沒有跟著變。
Router 即路由器,Route 即線路,線路由路由器管理,上面用了兩個路由器,你管你的,我管我的,相互間沒有通訊。
在 spug_web 中搜尋 <Router
僅出現一次:
// spug_web/src/index.js
ReactDOM.render(
<Router history={history}>
<ConfigProvider locale={zhCN} getPopupContainer={() => document.fullscreenElement || document.body}>
<App/>
</ConfigProvider>
</Router>,
document.getElementById('root')
)
我們也依葫蘆畫瓢,將 <Router>
包裹 <App/>
。
Switch
js 語法中就有 switch
,類似於 if...else
。我們對比有無 Switch 的兩種情況:
點選 About 導航,請問內容區顯示什麼?
// 沒有 Switch
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
...
</ul>
<hr />
<Route path="/about">
<About />1
</Route>
<Route path="/about">
<About />2
</Route>
...
</div>
);
}
內容區顯示:
About
1
About
2
// 有 Switch
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
...
</ul>
<hr />
<Switch>
<Route path="/about">
<About />1
</Route>
<Route path="/about">
<About />2
</Route>
...
</Switch>
</div>
);
}
內容區顯示:
About
1
渲染與該地址匹配的第一個子節點 <Route>
或者 <Redirect>
—— 官網
Tip:既然只匹配第一個子節點,那麼效能方面肯定會好些,因為不用在嘗試匹配後面的節點。
如果 URL 是 /about
,那麼 <About>
,<User>
,<NoMatch>
將全部渲染,因為他們都與路徑匹配:
// from 官網
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
exact
exact
即精確的。首先做一個小練習:
點選導航 About,下面兩個例子分別輸出什麼,是否匹配?
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
<Route path="/about/a">
<About />
</Route>
</div>
);
}
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about/a">About</Link>
</li>
</ul>
<hr />
<Route path="/about">
<About />
</Route>
</div>
);
}
第一個例子:內容區空白。未能匹配
第二個例子:內容區顯示”About“。匹配。
下面這段程式碼呢?
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/a/about/b">About</Link>
</li>
</ul>
<hr />
<Route path="/about">
<About />
</Route>
</div>
);
}
內容區空白。未能匹配。
總結:Link 可以多給,比如你要 /about
,我給你傳 /about/a
,但不能少給,而且順序不能亂,例如 /a/about/b
就不能匹配 /about
我們給第二個例子加上 exact
,請問輸出什麼?
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about/a">About</Link>
</li>
</ul>
<hr />
<Route exact path="/about">
<About />
</Route>
</div>
);
}
內容區空白。未能匹配。
如果為 true
,則只有在路徑完全匹配 location.pathname
時才匹配 —— 官網-exact: bool
注:只有需要的時候才開啟精確匹配,也就是說頁面正常,就不要去開啟它。
Redirect
渲染 <Redirect>
將使導航到一個新的地址。這個新的地址會覆蓋 history 棧中的當前地址,類似伺服器端(HTTP 3xx)的重定向 —— 官網-<Redirect>
下面我們用 <Redirect>
解決一個問題:
首先看下面這個例子:
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
);
}
第一次來到網站(http://localhost:3000/
),內容區是空白的,因為未能匹配任何 <Route>
。
現在需求:進入網站,預設顯示 <Dashboard />
。
只需要增加 2 行程式碼:
import {
+ Redirect,
...
} from "react-router-dom";
export default function BasicExample() {
return (
<div>
...
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
+ <Redirect to="/dashboard" />
</Switch>
</div>
);
}
瀏覽器輸入 http://localhost:3000/
,由於前兩個 <Route>
未能匹配,最後就會重定向到 http://localhost:3000/dashboard
。
replace
如果為 true,則單擊連結將替換歷史堆疊中的當前入口,而不是新增新入口 —— 官網-replace: bool
上面 BasicExample 元件,倘若我們依次點選 About 元件、Dashboard 元件,接著點選網頁左上角的返回(<-)按鈕,第一次會返回到 About 元件,再次點選則會返回到 Home 元件。
如果我們給 Dashboard 元件加上 replace 屬性。就像這樣:
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard" replace>Dashboard</Link>
</li>
</ul>
依次點選 About 元件、Dashboard 元件,然後第一次點選返回按鈕,則回到 Home 元件。
因為點選 Dashboard 導航時,不再是入棧操作(將 /dashboard
壓入棧中),而是替換操作(將棧中的 /about
替換成 /dashboard
),再次點選返回,就回到 /。
樣式丟失問題
通過一個示例演示問題:
首先在 index.html 增加樣式:
// public/index.html
+ <link rel="stylesheet" href="./css/index.css" />
// public/css/index.css
body{background-color: pink;}
修改 BasicExample 元件中 About 導航的路徑為多級路徑(/about
非多級路徑;/about/a
多級路徑):
// src/App.js
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about/a/b">About</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about/a/b">
<About />
</Route>
</Switch>
</div>
</Router>
);
}
開始測試:
啟動,http://localhost:3000/
背景是粉色,樣式正常,點選 ”About“導航,url 變成 http://localhost:3000/about/a/b
,背景依舊是粉色,重新整理頁面,粉色背景不見了,也就是樣式丟失了!
重新整理的時候,發現樣式請求的地址和返回內容如下:
http://localhost:3000/about/a/css/index.css
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="stylesheet" href="./css/index.css" />
<link rel="manifest" href="/manifest.json" />
<title>React App</title>
<script defer src="/static/js/bundle.js"></script></head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
注:請求不存在的資源,伺服器會將 public/index.html 返回給你。例如請求:http://localhost:3000/a/b/c/d
我們放慢重新整理這個動作:
- 重新整理,給伺服器傳送
http://localhost:3000/about/a/b
,沒有這個資源,所以伺服器返回 index.html。 - 瀏覽器解析 index.html,遇到
<link rel="stylesheet" href="./css/index.css" />
,需要載入當前目錄下的css/index.css
資源,當前目錄是http://localhost:3000/about/a
,於是請求http://localhost:3000/about/a/css/index.css
- 由於存在對應資源,伺服器再次返回 index.html,樣式也就丟失了
既然知道問題原因,只需要讓 css 資源路徑正常即可:
將
<link rel="stylesheet" href="./css/index.css" />
改成
<link rel="stylesheet" href="/css/index.css" />
或
<link rel="stylesheet" href="%PUBLIC_URL%/css/index.css" />
巢狀路由
巢狀路由也叫子路由。
將 BasicExample 元件中的 About 改造成巢狀路由。
首先看效果:
初始時 Home 導航選中:
· Home
· About
· Dashboard
________________________________
Home
點選 About 導航:
· Home
· About
· Dashboard
________________________________
About
________________________________
· article1
· article2
點選 article2 導航,顯示:
· Home
· About
· Dashboard
________________________________
About
________________________________
· article1
· article2
文章2...
巢狀路由相關程式碼如下:
// About 元件
function About() {
return (
// 新增一個路由器 Router
<Router>
<div>
<h2>About</h2>
<hr />
<ul>
<li>
<Link to="/about/article1">article1</Link>
</li>
<li>
<Link to="/about/article2">article2</Link>
</li>
</ul>
<Switch>
<Route path="/about/article1">
文章1...
</Route>
<Route path="/about/article2">
文章2...
</Route>
</Switch>
</div>
</Router>
);
}
路由元件 vs 一般元件
路由元件和一般元件最大的一個區別是:props 中是否有路由相關方法。
這裡有三個元件,請觀察每個元件的 props
:
// src/App.js
import React from "react";
import {
Switch,
Route,
Link
} from "react-router-dom";
export default function BasicExample() {
return (
<div>
<Header />
<ul>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Switch>
<Route path="/about" component={About} />
<Route path="/dashboard">
<Dashboard name="pjl" />
</Route>
</Switch>
</div>
);
}
// Home 元件
function Header(props) {
console.log('Header props,', props)
return (
<h2>Header</h2>
);
}
// About 元件
function About(props) {
console.log('About props,', props)
return (
<div>
<h2>About</h2>
</div>
);
}
// Dashboard 元件
function Dashboard(props) {
console.log('Dashboard props,', props)
return (
<div>
<h2>Dashboard</h2>
</div>
);
}
初始 url 為:http://localhost:3000/
,控制檯輸出:Header props, {}
點選 Dashboard 導航,控制檯輸出:Dashboard props, {name: 'pjl'}
點選 About 導航,控制檯輸出:
About props, {history: {…}, location: {…}, match: {…}, staticContext: undefined}
三個元件只有 About 元件是路由元件,其用法不同於另外兩種元件:
// 通過 component 屬性指定元件
<Route path="/about" component={About} />
<Dashboard name="pjl" />
<Header />
Tip:路由元件中的 history、location、match 屬性,下文都會講到。
pages/components 目錄
有人說路由元件和一般元件從專案結構上可以區分,比如將路由元件放在 src/pages
資料夾中,一般元件放在 src/components
中。
spug_web 中有 src/pages
和 src/components
目錄,是否就是根據一般元件和路由元件進行區分?請看擷取的程式碼片段:
首先是 src/routes.js
,猜測與路由相關:
// src/routes.js
import HomeIndex from './pages/home';
import DashboardIndex from './pages/dashboard';
import HostIndex from './pages/host';
import ExecTask from './pages/exec/task';
import ExecTemplate from './pages/exec/template';
import DeployApp from './pages/deploy/app';
import DeployRepository from './pages/deploy/repository';
import DeployRequest from './pages/deploy/request';
import ScheduleIndex from './pages/schedule';
import ConfigEnvironment from './pages/config/environment';
import ConfigService from './pages/config/service';
import ConfigApp from './pages/config/app';
import ConfigSetting from './pages/config/setting';
import MonitorIndex from './pages/monitor';
import AlarmIndex from './pages/alarm/alarm';
import AlarmGroup from './pages/alarm/group';
import AlarmContact from './pages/alarm/contact';
import SystemAccount from './pages/system/account';
import SystemRole from './pages/system/role';
import SystemSetting from './pages/system/setting';
import WelcomeIndex from './pages/welcome/index';
import WelcomeInfo from './pages/welcome/info';
引入的都是 pages 中的元件。
src/routes.js
又被 src\layout\index.js
引用:
// src/layout/index.js
import routes from '../routes';
// initRoutes 的實參 routes 就是上面匯入的 routes
function initRoutes(Routes, routes) {
for (let route of routes) {
if (route.component) {
if (!route.auth || hasPermission(route.auth)) {
// 通過 component 屬性指定元件
Routes.push(<Route exact key={route.path} path={route.path} component={route.component}/>)
}
} else if (route.child) {
initRoutes(Routes, route.child)
}
}
}
...
至此,初步判斷:spug_web 中的 pages 目錄和 components 目錄就是根據一般元件和路由元件進行區分的。
給路由元件傳遞引數
給路由元件傳遞引數有三種方式。
下面通過這三種方式實現同一個功能:給路由元件 About 傳遞 name
和 age
兩個引數。
params 方式
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about/pjl/18">About</Link>
</li>
</ul>
<hr />
<Switch>
<Route path="/about/:name/:age" component={About}>
</Route>
</Switch>
</div>
);
}
// About 元件
function About(props) {
// {history: {…}, location: {…}, match: {…}, staticContext: undefined}
console.log(props)
// {name: 'pjl', age: '18'}
console.log(props.match.params)
return (
<div>
<h2>About</h2>
</div>
);
}
點選 About 導航元件,控制檯輸出:
{history: {…}, location: {…}, match: {…}, staticContext: undefined}
// 接收兩個引數
{name: 'pjl', age: '18'}
一個 match 物件中包涵了有關如何匹配 URL 的資訊 —— 官網-match
search 方式
以 search 方式重寫 params 傳遞引數的例子:
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about/?name=pjl&age=18">About</Link>
</li>
</ul>
<hr />
<Switch>
<Route path="/about" component={About}>
</Route>
</Switch>
</div>
);
}
// About 元件
function About(props) {
// ?name=pjl&age=18
console.log(props.location.search)
var searchParams = new URLSearchParams(props.location.search)
const params = {}
for (const [key, value] of searchParams) {
params[key] = value
}
// params: {name: 'pjl', age: '18'}
console.log('params: ', params);
return (
<div>
<h2>About</h2>
</div>
);
}
需要自己將接收到的資料(例如 ?name=pjl&age=18
)處理一下。
Tip:params
和 search
傳參,在位址列中都能看見。例如 search:http://localhost:3000/about/?name=pjl&age=18
。重新整理頁面引數都不會丟失。
state 方式
注:與元件中的 state 沒有任何關係
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to={{ pathname: '/about', state: { name: 'pjl', age: 18 } }}>About</Link>
</li>
</ul>
<hr />
<Switch>
<Route path="/about" component={About}>
</Route>
</Switch>
</div>
);
}
// About 元件
function About(props) {
// {name: 'pjl', age: 18}
console.log(props.location.state)
return (
<div>
<h2>About</h2>
</div>
);
}
有兩個特點:
- 所傳引數不會再 url 中體現。比如這裡仍然是
http://localhost:3000/about
- 強制重新整理 url,所傳引數也不會消失。
- 筆者嘗試關閉瀏覽器,再次輸出
http://localhost:3000/about
,控制檯輸出undefined
- 筆者嘗試關閉瀏覽器,再次輸出
Tip:props.location === props.history.location
為 true
HashRouter 重新整理會導致 state 引數丟失
HashRouter 模式下,重新整理(非強刷)頁面會造成 state 引數的丟失。
將 App.js 中的 BrowserRouter 切換成 HashRouter 進行自測即可。
程式設計式導航 history
比如過3秒需要自動跳轉,這時就可以使用程式設計式導航。用法類似 History API。不過這裡我們操作的是 props.history
。
執行下面這個熟悉的例子,將會把 props.history
匯出給 window.aHistory
,我們直接在控制檯中操作 aHistory
:
// src/App.js
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/dashboard" component={Dashboard} />
</Switch>
</div>
);
}
// Home 元件
function Home(props) {
// 將 history 匯出,用於測試
window.aHistory = props.history
return (
<div>
<h2>Home</h2>
</div>
);
}
// About 元件
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
// Dashboard 元件
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
</div>
);
}
瀏覽器 url 是 http://localhost:3000/
,頁面內容如下:
· Home
· About
· Dashboard
________________________________
Home
測試開始:
> aHistory.push('/about')
url:http://localhost:3000/about
> aHistory.push('/dashboard')
url: http://localhost:3000/dashboard
> aHistory.goBack()
url: http://localhost:3000/about
// 等於 aHistory.goBack()
> aHistory.go(-1)
url: http://localhost:3000/
一般元件中使用程式設計式導航
一般元件中沒有 history,如果需要使用程式設計式導航,可以藉助 withRouter 將一般元件處理一下即可。請看示例:
import React from "react";
import {
Switch,
Route,
withRouter,
Link
} from "react-router-dom";
export default function BasicExample() {
return (
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/new-about">NewAbout</Link>
</li>
</ul>
<hr />
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/new-about">
<NewAbout />
</Route>
</Switch>
</div>
);
}
// About 元件
function About(props) {
console.log(props)
return (
<div>
<h2>About</h2>
</div>
);
}
var NewAbout = withRouter(About)
頁面顯示:
About
NewAbout
________________________________
依次點選 About 導航、NewAbout 導航,控制檯輸出:
{}
{history: {…}, location: {…}, match: {…}, staticContext: undefined}
其他章節請看: