1. 程式人生 > >【一起來學React】React-Router學習

【一起來學React】React-Router學習

在web下我們一般都使用react-router-dom,相比於react-router多了一些DOM操作方法,你可以嘗試單獨安裝react-router-dom,看依賴包裡面是不是會包含了react-router,本文就記錄下react-router-dom一些筆記(文章中api示例只給出了常用,詳細api請檢視官方文件)長篇文章警告!

安裝

npm install react-router-dom

基本使用

import React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom'
; const Router = () => { return ( <BrowserRouter> <Switch> <Route path='/' exact component={AsyncHome}/> <Route path='/hot' exact component={AsyncHot}/> </Switch> </BrowserRouter> ) }
export default Router // 然後在App.js import Router from './router'; const App = () => { render(){ return ( <React.Fragment> <Header/> {router} </React.Fragment> ) } } export default App //最後在inde中引用App即可

基本元件

React-Router中有三種類型的元件:路由器元件,路由匹配元件和導航元件

路由器元件

react-router-dom提供<BrowserRouter><HashRouter>路由器

  • <BrowserRouter>:原理是使用HTML5 history API,內容隨著url動態改變
  • <HashRouter>:有是根據hash值對路由進行控制的(會有#)

舉個例子:

import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

路由匹配元件

有兩個路由匹配元件:<Route><Switch>

  • <Route>:Route是路由的一個原材料,它是控制路徑對應顯示的元件。經常用的是exact、path以及component屬性
    exact:控制匹配到/路徑時不會再繼續向下匹
    path:路由的路徑
    component:顯示元件

  • <Switch>:Switch常常會用來包裹Route,它裡面不能放其他元素,用來只顯示一個路由。

舉個例子:

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/contact" component={Contact} />
</Switch>

API:

名稱 示例 屬性 作用
path /users/:id string 定義路徑
exact exact path="/one" bool 嚴格匹配

導航元件

<Link><NavLink>一般在元件內跳轉連結用的

  • <Link><Link to="/home">to可以接收一個string和object
  • <NavLink>:可以為當前選中的路由設定類名、樣式以及回撥函式等

舉個例子:

<Link
  to={{
    pathname: "/courses",
    search: "?sort=name",
    hash: "#the-hash",
    state: { fromDashboard: true }
  }}
/>

<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: "bold",
    color: "red"
  }}
>
  FAQs
</NavLink>

API:

<Link>

名稱 示例 屬性 作用
to to="/home" string 跳轉路徑
exact exact to="/one" bool 嚴格匹配

<NavLink>

名稱 示例 屬性 作用
to to="/home" string/object 跳轉路徑
exact exact to="/one" bool 嚴格匹配
activeClassName activeClassName=‘active’ string 當前路徑選中狀態的類名

程式碼拆分

其實就是按需載入,不管是官方還是開發者,都有給出自己的方式,這裡給出官方的示例程式碼,在我看來還是挺簡單的!

create-react-app

npm install @babel/plugin-syntax-dynamic-import
//router>index.js
import Loadable from "react-loadable";
import Loading from "./Loading";
const Home = Loadable({
  loader: () => import("./home"),
  loading: Loading//必須配置loading元件,不然報錯
});
const Router = () => {
    return (
        <BrowserRouter>
            <Switch>
                <Route path='/' exact component={Home}/>
            </Switch>
        </BrowserRouter>
    )     
}
export default Router

更多按需載入的方法請參考:https://segmentfault.com/a/1190000009539836

重定向

使用<Redirect>可以重定向路徑

import { Route, Redirect } from 'react-router'
//to是string的時候
<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>
//進入首頁,判斷是否已登陸,如果登陸重定向到使用者面板
//當to是object的時候
<Redirect
  to={{
    pathname: "/login",
    search: "?utm=your+face",
    state: { referrer: currentLocation }
  }}
/>

match

match是在使用router之後被放入props中的一個屬性(/home/:id)
match物件包含以下屬性:

  • params - (物件)從與路徑的動態段對應的URL解析的鍵/值對
  • isExact- (boolean)是否是嚴格模式
  • path - (字串)用於匹配的路徑模式。
  • url - (字串)URL的匹配部分。

withRouter

使用過vue-router的同學可能剛開始會很奇怪,為什麼react-router沒有直接在元件中js跳轉路由的方法,比如this.$router.push

withRouter:是一個可以讓你訪問history物件的屬性和最近<Route>match的高階元件

利用withRouter達到路由js跳轉

import React from "react";
import {withRouter } from 'react-router-dom';

class TLogin extends React.Component {

    handleJump(){//在方法內呼叫
        this.props.history.push('/home')
    }

    render() {
        //dosomething
  }
}
const Login = withRouter(TLogin)
export default Login;

//使用react-redux的時候
onst Login = withRouter(connect(...)(TLogin))
export default Login;

路由巢狀

v4中不支援以前這種寫法

   <Route path="/" component={App}>
     <Route path="about" component={About} />
     <Route path="inbox" component={Inbox}>
       <Route path="messages/:id" component={Message} />
     </Route>
   </Route>

v4中子路由,應寫在對應的元件內部中,當然你可以用react-router-config物件的方式配置巢狀,和vue-router一樣的。

npm install --save react-router-config

//app.js
import {renderRoutes} from 'react-router-config';
import Router from './router';
const App = () => {
   render(){
       return (
           <React.Fragment>
               <Header/>
               {renderRoutes(Router)}
           </React.Fragment>
       )   
   }     
}
export default App
//./router
export const Router = [
 {
   component: home,
   path:'/',
 },{
   component:parent,
   path:'/parent',  
   routes: [
     {
       path: "/parent/:id",
       component: Child,
       routes: [
         {
           path: "/parent/:id/grand-child",
           component: GrandChild
         }
       ]
     }
   ]
 }
];

非同步載入元件

1.新建AsyncComponents元件


import React, {Component} from 'react';
export default  function asyncComponents(importComponent) {
    class AsyncComponent extends Component {
        constructor(props) {
            super(props);
            this.state = {
                component: null,
            }
        }
        async componentDidMount() {//非同步
            const {default: component} = await importComponent();
            
            this.setState({
                component: component
            });
        }

        render() {
            const C = this.state.component;
            return C ? <C {...this.props} /> : null;
        }
    }
    return AsyncComponent
}

2、在router>index.js

import React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import asyncComponents from  "../components/AsyncComponents"

const AsyncHome = asyncComponents(() => import('../page/home/home'));
const AsyncHot = asyncComponents(() => import('../page/hot/hot'));

const router = (
    <BrowserRouter>
        <Switch>
            <Route path='/' exact component={AsyncHome}/>
            <Route path='/hot' exact component={AsyncHot}/>
        </Switch>
    </BrowserRouter>
);
export default router