快速上手 React 路由
本文以簡潔爲目標,幫助快速上手react-router-dom默認你接觸過路由相關的開發
安裝
輸入以下命令進行安裝:
// npm
npm install react-router-dom
// yarn
yarn add react-router-dom
react-router 相關標籤
react-router常用的組件有以下八個:
import {
BrowserRouter,
HashRouter,
Route,
Redirect,
Switch,
Link,
NavLink,
withRouter,
} from 'react-router-dom'
簡單路由跳轉
實現一個簡單的一級路由跳轉
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
<Link to="/home" class>跳轉Home頁面</Link>
<Link to="/about" class>跳轉About頁面</Link>
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
</Router>
</div>
);
}
export default App;
效果如下:
要點總結:
-
Route組件必須在Router組件內部 -
Link組件的to屬性的值爲點擊後跳轉的路徑 -
Route組建的path屬性是與Link標籤的to屬性匹配的;component屬性表示Route組件匹配成功後渲染的組件對象
嵌套路由跳轉
React 的路由匹配層級是有順序的
例如,在 App 組件中,設置了兩個路由組件的匹配路徑,分別是 /home 和 /about,代碼如下:
import {
BrowserRouter as Router,
Route,
Link,
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
<Link to="/home">跳轉Home頁面</Link>
<Link to="/about">跳轉About頁面</Link>
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
</Router>
</div>
);
}
export default App;
然後 Home 組件中同樣也想設置兩個路由組件的匹配路徑,分別是 /home/one 和 /home/two,此時就可以看出,這個 /home/one 和 /home/two 爲上一級路由 /home 的二級嵌套路由,代碼如下:
import React from 'react'
import {
Route,
Link,
} from 'react-router-dom'
import One from './one'
import Two from './two'
function Home () {
return (
<>
我是Home頁面
<Link to="/home/one">跳轉到Home/one頁面</Link>
<Link to="/home/two">跳轉到Home/two頁面</Link>
<Route path="/home/one" component={One}/>
<Route path="/home/two" component={Two}/>
</>
)
}
export default Home
特別注意: Home 組件中的路由組件 One 的二級路由路徑匹配必須要寫 /home/one ,而不是 /one ,不要以爲 One 組件看似在 Home 組件內就可以簡寫成 /one
動態鏈接
NavLink可以將當前處於active狀態的鏈接附加一個active類名,例如:
import {
BrowserRouter as Router,
Route,
NavLink
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
<NavLink to="/home" class>跳轉Home頁面</NavLink>
<NavLink to="/about" class>跳轉About頁面</NavLink>
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
</Router>
</div>
);
}
export default App;
/* 設置active類的樣式 */
.active {
font-weight: blod;
color: red;
}
效果如下:
路由匹配優化
當點擊跳轉鏈接時,會自動去嘗試匹配所有的Route對應的路徑,如圖所示:
正常情況下,只需匹配到一個規則,渲染即可,即匹配成功一個後,無需進行後續的匹配嘗試,此時可以用Switch組件,如下所示:
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
<NavLink to="/home" class>跳轉Home頁面</NavLink>
<NavLink to="/about" class>跳轉About頁面</NavLink>
<Switch>
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Home}/>
{/* 此處省略一萬個Route組件 */}
<Route path="/home" component={Home}/>
</Switch>
</Router>
</div>
);
}
export default App;
效果如下:
要點總結:
- 將多個
Route組件同時放在一個Switch組件中,即可避免多次無意義的路由匹配,以此提升性能
重定向
當頁面跳轉時,若跳轉鏈接沒有匹配上任何一個 Route 組件,那麼就會顯示 404 頁面,所以我們需要一個重定向組件 Redirect ,代碼如下:
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
Redirect,
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
<NavLink to="/home" class>跳轉Home頁面</NavLink>
<NavLink to="/about" class>跳轉About頁面</NavLink>
<NavLink to="/shop" class>跳轉Shop頁面</NavLink> {/* 點擊,跳轉到/shop,但該路徑沒有設置 */}
<Switch>
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
<Redirect to="/home" /> {/* 當以上Route組件都匹配失敗時,重定向到/home */}
</Switch>
</Router>
</div>
);
}
export default App;
效果如下:
路由傳參
所有路由傳遞的參數,都會在跳轉路由組件的 props 中獲取到,每種傳參方式接收的方式略有不同
路由傳參的方式一共有三種,依次來看一下
第一種
第一種是在 Link 組件的跳轉路徑上攜帶參數,並在 Route 組件的匹配路徑上通過 :參數名 的方式接收參數,代碼如下:
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
{/* 在 /home 的路徑上攜帶了 張三、18 共兩個參數 */}
<NavLink to="/home/張三/18" class>跳轉Home頁面</NavLink>
<NavLink to="/about" class>跳轉About頁面</NavLink>
<Switch>
{/* 在 /home 匹配路徑上相同的位置接收了 name、age 兩個參數 */}
<Route path="/home/:name/:age" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Router>
</div>
);
}
export default App;
嘗試跳轉,並打印一下路由組件的 props
可以看到,第一種方式的參數是通過 props.match.params 來獲取的
第二種
第二種方式就是通過在 Link 組件的跳轉鏈接後面跟上以 ? 開頭,類似 ?a=1&b=3 這樣的參數進行傳遞,代碼如下:
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
{/* 在跳轉路徑後面以?開頭傳遞兩個參數,分別爲name=張三、age=18 */}
<NavLink to="/home?>跳轉Home頁面</NavLink>
<NavLink to="/about" class>跳轉About頁面</NavLink>
<Switch>
{/* 此處無需做接收操作 */}
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Router>
</div>
);
}
export default App;
嘗試跳轉,並打印一下路由組件的 props
可以看到,第二種方式的參數是通過 props.location.search 來獲取的,不過這裏的參數需要自己簡單做進一步轉化,這裏就不做過多說明了
第三種
第三種方式就是以對象的形式編寫 Link 組件的 to 跳轉屬性,並通過 state 屬性來傳遞參數,代碼如下:
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
{/* 以對象的形式描述to屬性,路徑屬性名爲pathname,參數屬性名爲state */}
<NavLink to={{pathname: "/home", state: {name: '張三', age: 18}}} class>跳轉Home頁面</NavLink>
<NavLink to="/about" class>跳轉About頁面</NavLink>
<Switch>
{/* 此處無需特地接收屬性 */}
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Router>
</div>
);
}
export default App;
嘗試跳轉,並打印一下路由組件的 props
可以看到,第三種方式的參數是通過 props.location.state 來獲取的
函數式路由
以上主要都是通過 react-router-dom 中的 Link 組件來往某個路由組件跳轉
但有時,我們需要更靈活的方式進行跳轉路由,例如通過調用一個函數,隨時隨地進行路由跳轉,這就叫函數式路由
函數式路由用到的方法有以下 5 個(下方截圖來自路由組件的 props)
5 個方法分別是 push、replace、goForward、goBack、go,接下來按順序介紹一下這幾個方法
push
push 方法就是使頁面跳轉到對應路徑,並在瀏覽器中留下記錄(即可以通過瀏覽器的回退按鈕,返回上一個頁面)
舉個例子:在路由組件 Home 中設置一個按鈕 button ,點擊後調用 push 方法,跳轉到 /about 頁面
import React from 'react'
function Home (props) {
let pushLink = () => {
props.history.push('/about')
}
return (
<div class>
我是Home頁面
<button onClick={pushLink}>跳轉到about頁面</button>
</div>
)
}
export default Home
跳轉效果如下:
可以看到,通過 push 方法跳轉以後,可以通過瀏覽器的回退按鈕,返回上一個頁面
replace
replace 方法與 push 方法類似,不一樣的地方就是,跳轉後不會在瀏覽器中保存上一個頁面的記錄(即無法通過瀏覽器的回退按鈕,返回上一個頁面)
改動一下代碼
import React from 'react'
function Home (props) {
let replaceLink = () => {
props.history.replace('/about')
}
return (
<div class>
我是Home頁面
<button onClick={replaceLink}>跳轉到about頁面</button>
</div>
)
}
export default Home
跳轉效果如下:
可以看到,剛開始的路徑是 '/' ,然後跳轉到 '/home' ,再點擊按鈕,通過 replace 方法跳轉到 /about 頁面。最後通過瀏覽器的回退按鈕返回到了 / 頁面,說明中間的 /home 沒有被存在瀏覽器的記錄裏
goForward
調用 goForward 方法,就相當於點擊了瀏覽器的返回下一個頁面按鈕,如下圖所示:
這裏就不做過多演示了
goBack
調用 goBack 方法,就相當於點擊了瀏覽器的返回上一個頁面的按鈕,如下圖所示:
go
go 方法顧名思義,是用於跳轉到指定路徑的。
該方法接受一個參數(參數類型爲 Number),情況如下:
-
當參數爲正數
n時,表示跳轉到下n個頁面。例如go(1)相當於調用了一次goForward方法 -
當參數爲負數
n時,表示跳轉到上n個頁面。例如go(-3)相當於調用了三次goBack方法 -
當參數爲
0時,表示刷新當前頁面
普通組件使用路由
這裏區分兩個概念,分別爲 普通組件 和 路由組件
通過 Route 組件渲染的組件爲路由組件 ,其餘的基本上都爲 普通組件
例如,下方代碼中:Home 組件爲路由組件 ; App 組件爲普通組件
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
} from 'react-router-dom'
import Home from './home'
export default function App() {
return (
<div class>
<Router>
<NavLink to='/home' class>跳轉Home頁面</NavLink>
<Switch>
<Route path="/home" component={Home}/>
</Switch>
</Router>
</div>
);
}
然後,路由組件跟普通組件最大的區別就是,組件的 props 屬性中是否有下圖所示的內容:(前者有,後者無)
此時,react-router-dom 提供了一個 withRouter 方法,可以使普通組件也能像路由組件一樣有那些方法或數據可以使用
使用方法如下:
import {
BrowserRouter as Router,
Route,
NavLink,
Switch,
withRouter, // 1. 引入 witRouter
} from 'react-router-dom'
import About from './about'
function App(props) {
console.log(props); // 3. 嘗試打印普通組件App的props,發現此時props中已有內容了,即普通組件也能擁有跟路由組件一樣類似的功能
return (
<div class>
<Router>
<NavLink to="/about" class>跳轉About頁面</NavLink>
<Switch>
<Route path="/about" component={About}/>
</Switch>
</Router>
</div>
);
}
export default withRouter(App); // 2. 通過withRouter方法對普通組件做一層包裝處理
補充
replace
在函數式路由裏跳轉類型主要有兩種,分別是 push 和 replace,那麼在非函數式路由中,同樣也可以自定義跳轉類型,具體的實現代碼如下:
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
<Link to="/home" class>跳轉Home頁面</Link>
<Link to="/about" class>跳轉About頁面</Link>
<Route path="/home" component={Home} replace={true}/> {/* replace爲true,跳轉類型爲replace */}
<Route path="/about" component={About} replace={false}/> {/* replace爲false,跳轉類型爲push */}
</Router>
</div>
);
}
export default App;
Route 組件上有個 replace 屬性可以設定跳轉類型,當值爲 true 時,跳轉類型爲 replace ; 爲 false 時,跳轉類型爲 push
excat
路由的匹配默認是模糊匹配的,舉個例子:
import {
BrowserRouter as Router,
Route,
Link,
} from 'react-router-dom'
import Home from './home'
import About from './about'
function App() {
return (
<div class>
<Router>
<Link to="/home/abc">跳轉Home頁面</Link> {/* 跳轉到/home/abc,但實際home下沒有abc這個路由組件 */}
<Link to="/about/abc">跳轉About頁面</Link> {/* 跳轉到/about/abc,但實際home下也沒有abc這個路由組件 */}
<Route path="/home" component={Home} /> {/* 路由匹配規則爲/home,沒有設置exact屬性,當前爲模糊匹配 */}
<Route path="/about" component={About} exact/> {/* 路由匹配規則爲/about,設置了exact屬性,當前爲精準匹配 */}
</Router>
</div>
);
}
export default App;
效果如下:
圖中看出,因爲跳轉 /home/abc 時,第一個 Route 組件是模糊匹配的,所以先匹配到了 /home,因此 Home 組件渲染了 ; 而跳轉 /about/abc 時,第二個 Route 組件是精準匹配的,即 /about/abc 不等於 /about,所以 About 組件也沒有渲染
總結:
-
如果想要精準匹配的話,只需要將
Route組件的exact屬性設置爲true即可 -
精準匹配要謹慎使用,因爲可能會影響嵌套路由的使用
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/qnhzG8rZofsvdmEqIOrAeg