React 系列十二:React - Router

快來加入咱們吧!

"小和山的菜鳥們",爲前端開發者提供技術相關資訊以及系列基礎文章。爲更好的用戶體驗,請您移至咱們官網小和山的菜鳥們 ( xhs-rookies.com/ ) 進行學習,及時獲取最新文章。javascript

"Code tailor" ,若是您對咱們文章感興趣、或是想提一些建議,微信關注 「小和山的菜鳥們」 公衆號,與咱們取的聯繫,您也能夠在微信上觀看咱們的文章。每個建議或是贊同都是對咱們極大的鼓勵!css

前言

這節咱們將介紹 Reactreact - router,路由跳轉的配置以及使用前端

本文會向你介紹如下內容:java

  • 認識 react-router
  • react-router 基本使用
  • react-router 高級使用
  • react-router-config

認識 react - router

若是你是第一次接觸 router 這個名詞,能夠先去這裏補充一下本身的路由知識再來往下閱讀哦node

**注意:**如下內容基於 react-router v5 版本,若是和讀者當前使用的不符合,請以官網爲主react

安裝 react-routerweb

yarn add react-router-dom

npm install react-router-dom
複製代碼

什麼是 react-routernpm

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-routerReact 體系中的路由庫,它經過管理 URL,實現組件的切換和狀態的變化瀏覽器

react-router 基本使用

React Router 中的組件主要分爲三類:

路由器 BrowserRouterHashRouter

  • BrowserRouter 使用常規URL路徑,建立一個像 example.com/some/path 這樣真實的 URL ,可是他們要求正確的配置服務器
  • HashRouter 將當前位置存儲在 URL 的哈希部分中,所以 URL 看起來相似於http://example.com/#/your/page ,因爲哈希從不發送到服務器,所以這意味着不須要特殊的服務器配置

二者之間的主要區別是它們存儲 URL 和與 Web 服務器通訊的方式

路由匹配器,例如 Switch 和 Route:

當渲染 Switch 組件時,它將搜索它的 Route 子元素,以查找路徑與當前 URL 匹配的元素,它將呈現找到的第一個 Route 並忽略全部的其餘路由。這意味着您應該將包含更多特定路徑的 Route 放在不那麼特定的路由以前

Switch

咱們來看下面的路由規則:

  • 當咱們匹配到某一個路徑時,咱們會發現有一些問題;
  • 好比/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 元素。這也就意味着若是你在此是用內聯函數渲染的組件,那麼它將會在每次渲染時都建立一個新的函數,即卸載組件安裝新有組件,而不是更新。因此當你使用內聯函數渲染組件時,請選擇 renderchildren 方法

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

  • match :包含 如何匹配 URL 的信息
  • location :表明應用程序如今所在的位置
  • history : 用於在 JavaScript 中以各類方式管理會話歷史記錄

路由導航,例如:Link 、NavLink 、Redirect

  • <Link> 組件將在您的應用程序中建立連接。不管在何處呈現 <Link>,錨點都將呈如今 HTML 文檔中,而其最終會被渲染成 a 元素
  • NavLinkLink 基礎之上增長了一些樣式屬性,當其 prop 與當前位置匹配時,能夠給它設置一個 activeClassName(被選中) 的樣式。
  • 任什麼時候候要強制導航,你均可以使用 <Redirect>,當呈現 <Redirect> 時,將根據 propto 值進行導航。
NavLink

路徑選中時,對應的 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>
複製代碼

可是,咱們會發如今選中 aboutprofile 時,第一個也會變成紅色:

  • 緣由是/路徑也匹配到了 /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

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" />
    )
  }
}
複製代碼

react-router 高級使用

嵌套路由

此示例顯示嵌套路由的工做原理。路由 /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-router-config

路由配置的方式多種多樣,讓咱們看一下來自官網的最佳實踐

// 路由配置只是數據
// 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 相關知識咱們已學習完畢,下一節咱們將爲以前的留言板加上登陸功能!

相關文章
相關標籤/搜索