"小和山的菜鳥們",爲前端開發者提供技術相關資訊以及系列基礎文章。爲更好的用戶體驗,請您移至咱們官網小和山的菜鳥們 ( xhs-rookies.com/ ) 進行學習,及時獲取最新文章。javascript
"Code tailor" ,若是您對咱們文章感興趣、或是想提一些建議,微信關注 「小和山的菜鳥們」 公衆號,與咱們取的聯繫,您也能夠在微信上觀看咱們的文章。每個建議或是贊同都是對咱們極大的鼓勵!css
這節咱們將介紹 React
中 react - router
,路由跳轉的配置以及使用前端
本文會向你介紹如下內容:java
react-router
react-router
基本使用react-router
高級使用react-router-config
若是你是第一次接觸 router 這個名詞,能夠先去這裏補充一下本身的路由知識再來往下閱讀哦node
**注意:**如下內容基於 react-router v5 版本,若是和讀者當前使用的不符合,請以官網爲主react
安裝 react-router
:web
yarn add react-router-dom
npm install react-router-dom
複製代碼
什麼是 react-router
?npm
React Router is a set of navigation components that are combined with your application in a declarative manner. Whether you want to provide bookmarkable URLs for your web applications or use composable navigation methods in React Native, React Router can be used anywhere React renders數組
react-router
是一組以聲明方式與您的應用程序組合的導航組件,換句話,react-router
是 React
體系中的路由庫,它經過管理 URL,實現組件的切換和狀態的變化瀏覽器
React Router
中的組件主要分爲三類:
BrowserRouter
和 HashRouter
BrowserRouter
使用常規URL路徑,建立一個像 example.com/some/path
這樣真實的 URL ,可是他們要求正確的配置服務器HashRouter
將當前位置存儲在 URL
的哈希部分中,所以 URL
看起來相似於http://example.com/#/your/page
,因爲哈希從不發送到服務器,所以這意味着不須要特殊的服務器配置二者之間的主要區別是它們存儲 URL
和與 Web
服務器通訊的方式
當渲染 Switch
組件時,它將搜索它的 Route
子元素,以查找路徑與當前 URL
匹配的元素,它將呈現找到的第一個 Route
並忽略全部的其餘路由。這意味着您應該將包含更多特定路徑的 Route
放在不那麼特定的路由以前
咱們來看下面的路由規則:
/about
路徑匹配到的同時,/:userid
也被匹配到了,而且最後的一個 NoMatch
組件老是被匹配到;<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/profile" component={Profile} />
<Route path="/:userid" component={User}/>
<Route component={NoMatch}/>
複製代碼
緣由是什麼呢?默認狀況下,react-router
中只要是路徑被匹配到的 Route
對應的組件都會被渲染;
可是實際開發中,咱們每每但願有一種排他的思想:
Switch
來將全部的 Route
進行包裹便可;<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/profile" component={Profile} />
<Route path="/:userid" component={User} />
<Route component={NoMatch} />
</Switch>
複製代碼
Route
它最基本的職責是在其路徑與當前 URL 匹配時呈現一些 UI
Route 的渲染方法一共有三類
Route component
僅在位置匹配時根據 route props
渲染
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
// All route props (match, location and history) are available to User
function User(props) {
return <h1>Hello {props.match.params.username}!</h1>;
}
ReactDOM.render(
<Router> <Route path="/user/:username" component={User} /> </Router>,
node
);
複製代碼
當你在使用此方法加載時,router
一般會根據給定的 component
去調用 React.createElement
建立一個新的 React
元素。這也就意味着若是你在此是用內聯函數渲染的組件,那麼它將會在每次渲染時都建立一個新的函數,即卸載組件安裝新有組件,而不是更新。因此當你使用內聯函數渲染組件時,請選擇 render
或 children
方法
Route render
你能夠傳入一個在位置匹配時調用的函數,而不是使用組件 prop
爲您建立一個新的 React
元素
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route } from "react-router-dom";
// convenient inline rendering
ReactDOM.render(
<Router> <Route path="/home" render={() => <div>Home</div>} /> </Router>,
node
);
// wrapping/composing
// You can spread routeProps to make them available to your rendered Component
function FadingRoute({ component: Component, ...rest }) {
return (
<Route {...rest} render={routeProps => ( <FadeIn> <Component {...routeProps} /> </FadeIn> )} />
);
}
ReactDOM.render(
<Router> <FadingRoute path="/cool" component={Something} /> </Router>,
node
);
複製代碼
須要注意的是: 的優先級比 高,因此不要在同一個 Route
中同時調用兩種方法
Route children
工做原理同 ,只是不管是否匹配都會調用
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Link,
Route
} from "react-router-dom";
function ListItemLink({ to, ...rest }) {
return (
<Route path={to} children={({ match }) => ( <li className={match ? "active" : ""}> <Link to={to} {...rest} /> </li> )} />
);
}
ReactDOM.render(
<Router> <ul> <ListItemLink to="/somewhere" /> <ListItemLink to="/somewhere-else" /> </ul> </Router>,
node
);
複製代碼
須要注意的是: 優先級比上面兩個優先級都高
而這三種渲染方式都會傳遞相同的 route props
URL
的信息<Link>
組件將在您的應用程序中建立連接。不管在何處呈現 <Link>
,錨點都將呈如今 HTML
文檔中,而其最終會被渲染成 a
元素NavLink
在 Link
基礎之上增長了一些樣式屬性,當其 prop
與當前位置匹配時,能夠給它設置一個 activeClassName
(被選中) 的樣式。<Redirect>
,當呈現 <Redirect>
時,將根據 prop
的 to
值進行導航。路徑選中時,對應的 a 元素變爲紅色
activeStyle
:活躍時(匹配時)的樣式;activeClassName
:活躍時添加的 class;exact
:是否精準匹配;<NavLink to="/" activeStyle={{color: "red"}}>home</NavLink>
<NavLink to="/about" activeStyle={{color: "red"}}>about</NavLink>
<NavLink to="/profile" activeStyle={{color: "red"}}>profile</NavLink>
複製代碼
可是,咱們會發如今選中 about
或 profile
時,第一個也會變成紅色:
/about
或 /profile
NavLink
中添加上 exact
屬性<NavLink exact to="/" activeStyle={{ color: 'red' }}>
home
</NavLink>
複製代碼
默認的 activeClassName
:
NavLink
就會添加上一個動態的 active class
;a.active {
color: red;
}
複製代碼
固然,若是你擔憂這個 class
在其餘地方被使用了,出現樣式的層疊,也能夠自定義 class
<NavLink exact to="/" activeClassName="link-active">home</NavLink>
<NavLink to="/about" activeClassName="link-active">about</NavLink>
<NavLink to="/profile" activeClassName="link-active">profile</NavLink>
複製代碼
Redirect
用於路由的重定向,當這個組件出現時,就會執行跳轉到對應的 to
路徑中,而 Redirect
最多見的場景即鑑權
用戶瀏覽器輸入 User
界面 url
;
若用戶未登陸,需重定向到登陸頁面。若已登陸,則可進入 User
界面
App.js
中提早定義好 Login
頁面對應的 Route
:
<Switch>
...其餘Route
<Route path="/login" component={Login} />
<Route component={NoMatch} />
</Switch>
複製代碼
在 User.js
中寫上對應的邏輯代碼:
import React, { PureComponent } from 'react'
import { Redirect } from 'react-router-dom'
export default class User extends PureComponent {
constructor(props) {
super(props)
this.state = {
isLogin: false,
}
}
render() {
return this.state.isLogin ? (
<div> <h2>微信公衆號:小和山的菜鳥們</h2> <h2>用戶名: Coder tailor</h2> </div>
) : (
<Redirect to="/login" />
)
}
}
複製代碼
此示例顯示嵌套路由的工做原理。路由 /topics
加載 Topics
組件,該組件根據路徑 :id
值有條件地呈現任何進一步的 <Route>
。
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams
} from "react-router-dom";
export default function App() {
return (
<Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/topics">Topics</Link> </li> </ul> <Switch> <Route path="/about"> <About /> </Route> <Route path="/topics"> <Topics /> </Route> <Route path="/"> <Home /> </Route> </Switch> </div> </Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Topics() {
let match = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/components`}>Components</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
{/* Topics 頁面有本身的 <Switch>,其中包含更多基於 /topics URL 路徑
的路由。您能夠將此處的第二個 <Route> 視爲全部主題的「索引」頁面,或者
未選擇主題時顯示的頁面 */}
<Switch>
<Route path={`${match.path}/:topicId`}>
<Topic />
</Route>
<Route path={match.path}>
<h3>Please select a topic.</h3>
</Route>
</Switch>
</div>
);
}
function Topic() {
let { topicId } = useParams();
return <h3>Requested topic ID: {topicId}</h3>;
}
複製代碼
當咱們討論動態路由時,咱們是指在您的應用渲染時發生的路由,而不是在運行中的應用以外配置或約定的。
這意味着幾乎全部內容都是 React Router
中的一個組件。下面是對該 API
的回顧,以瞭解其工做原理:
首先,爲您要定位的環境獲取一個 Router
組件,並將其呈如今應用程序的頂部。
// react-dom (what we'll use here)
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter> <App /> </BrowserRouter>,
el
);
const App = () => (
<div> <nav> <Link to="/dashboard">Dashboard</Link> </nav> <div> <Route path="/dashboard" component={Dashboard} /> </div> </div>
);
複製代碼
該 Route
將呈現 <Dashboard {... props} />
,其中 props
是路由器特定的東西,好比 { match, location, history }
。若是用戶不在 / dashboard
上,則 Route
將呈現 null
。
路由配置的方式多種多樣,讓咱們看一下來自官網的最佳實踐
// 路由配置只是數據
// React 很是擅長將數據映射到組件中,而 <Route> 是一個組件.
//咱們的路由配置只是一個帶有 path 和 component props 的邏輯"路由"數組
//排序方式與你在 `<Switch>` 中的順序相同。
//路由配置
const routes = [
{
path: "/sandwiches",
component: Sandwiches
},
{
path: "/tacos",
component: Tacos,
routes: [
{
path: "/tacos/bus",
component: Bus
},
{
path: "/tacos/cart",
component: Cart
}
]
}
];
複製代碼
嵌入 App 中
export default function App() {
ReactDOM.render(
<Router> <div> <ul> <li> <Link to="/tacos">Tacos</Link> </li> <li> <Link to="/sandwiches">Sandwiches</Link> </li> </ul> <Switch> {routes.map((route, i) => ( <RouteWithSubRoutes key={i} {...route} /> ))} </Switch> </div> </Router>
,document.getElementById('root')
)
}
複製代碼
組件在這兒
function Sandwiches() {
return <h2>Sandwiches</h2>;
}
function Tacos({ routes }) {
return (
<div> <h2>Tacos</h2> <ul> <li> <Link to="/tacos/bus">Bus</Link> </li> <li> <Link to="/tacos/cart">Cart</Link> </li> </ul> <Switch> {routes.map((route, i) => ( <RouteWithSubRoutes key={i} {...route} /> ))} </Switch> </div>
);
}
function Bus() {
return <h3>Bus</h3>;
}
function Cart() {
return <h3>Cart</h3>;
}
//<Route> 的特殊包裝器,它知道如何經過將"子"路由
//傳遞到它呈現的組件的 `routes` 屬性來處理它們。
function RouteWithSubRoutes(route) {
return (
<Route path={route.path} render={props => ( // pass the sub-routes down to keep nesting <route.component {...props} routes={route.routes} /> )} />
);
}
複製代碼
在這一節咱們學習了 React-Router
相關知識,至此,React
相關知識咱們已學習完畢,下一節咱們將爲以前的留言板加上登陸功能!