React Router 4.x 開發,這些雷區咱們都幫你踩過了

前言

在前端框架層出不窮的今天,React 以其虛擬 DOM 、組件化開發思想等特性迅速佔據了主流位置,成爲前端開發工程師熱衷的 Javascript 庫。做爲 React 體系中的重要組成部分:React Router 也成爲開發者首選的路由庫,其主要功能是經過管理 url 實現組件的切換和狀態的變化。javascript

正文

在 React Router 4.x 發佈以前,咱們在項目中使用的是 React Router 3.x。隨着第四版 React Router 的正式亮相,其精簡的 API 、語義化的路由匹配方案以及動態路由等變化,都彰顯着這次升級的顛覆性。因此,咱們決定在新的 React 項目中使用 4.x(React Router 4.x)開發,親身實踐以後發現: 4.x 不只是 API 的簡單改變,還有整個設計理念的變化;初次使用確實有一些彆扭,更可怕的是按照 API 文檔寫出的代碼,有時運行時會出現一些莫名其妙的紅色錯誤(此刻的心情 down 到谷底~)。爲了不你們在使用時遇到一樣的問題多繞彎子,咱們把開發過程當中遇到的問題以及相應的解決方法作了彙總。css

4.x 使用問題彙總

1. 包引用方式

在以前的 3.x 中,在入口文件中定義路由時,咱們會這麼寫:html

import React from 'react';
import ReactDOM from 'react-dom';
import {Router, Route, browserHistory} from 'react-router';
import * as routePaths from './js/constants/routePaths';
import Index from './js/pages/Index';

ReactDOM.render((
    <Router history={history}>
        <div className="container">
            <Route path={routePaths.INDEX} component={Index} />
        </div>
    </Router>
    ),
    document.getElementById('app')
);

可是保存後運行發現頁面報錯了,以下圖所示:前端

解決方法:java

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
import * as routePaths from './js/constants/routePaths';
import Index from './js/pages/Index';

ReactDOM.render((
    <BrowserRouter>
        <div className="container">
            <Route path={routePaths.INDEX} component={Index} />
        </div>
    </BrowserRouter>
    ),
    document.getElementById('app')
);

頁面顯示正常,問題解決。接下來咱們對該解決方法進行詳細的解釋:node

4.x 中採用了單代碼倉庫模型架構,因此裏面包含了若干個相互獨立的包,以下所示:react

  • react-router  React Router 核心
  • react-router-dom  用於 DOM 綁定的 React Router
  • react-router-native  用於 React Native 的 React Router
  • react-router-redux  React Router 和 Redux 的集成
  • react-router-config  用於配置靜態路由

所以,在實際的 web 項目開發中,react-router  和  react-router-dom  沒必要同時引用。在 react-router-dom  中包含相似  <BrowserRouter>  的 DOM 類組件,因此只須要引入 react-router-dom  包就能夠了。webpack

使用方法:git

import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

關於  <BrowserRouter> 是什麼?下面的問題中會有詳細介紹,莫急~github

2. 頁面中多個模塊同時渲染問題

咱們同時定義了多個模塊,當路由切換時發現這些模塊會同時渲染出來。好比像下面這樣定義:

ReactDOM.render((
    <BrowserRouter>
        <div className="container">
            <Route path="/" component={Index} />
            <Route path="/card" component={Card} />
        </div>
    </BrowserRouter>
    ),
    document.getElementById('app')
);

當訪問  path="/card" 的頁面時,path="/" 的頁面也會被渲染出來。不一樣於 3.x 中路由匹配時的獨一無二特性,4.x 中有了一層包含關係:如匹配  path="/card"  的路由會匹配  path="/"的路由。那麼這個問題怎麼解決呢?有如下兩種方法:

(1)使用  <Router>  的  exact 關鍵字
ReactDOM.render((
    <BrowserRouter>
        <div className="container">
            <Route path="/" exact component={Index} />
            <Route path="/card" component={Card} />
        </div>
    </BrowserRouter>
    ),
    document.getElementById('app')
);
(2)使用獨立路由: <Switch>
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';

ReactDOM.render((
    <BrowserRouter>
        <Switch>
            <div className="container">
                <Route path="/" exact component={Index} />
                <Route path="/card" component={Card} />
            </div>
        </Switch>
    </BrowserRouter>
    ),
    document.getElementById('app')
);

完美!模塊能夠實現獨立渲染了。咱們來看下這樣解決問題的緣由:

首先須要瞭解下 <Router> 。它是全部路由組件共用的底層接口,在 4.x 中,你能夠將各類組件及標籤放進  <Router>  組件中。好比:

<Router>
    <div>
        <ul>
            <li><Link to="/">Home</Link></li>
        </ul>
        <hr/>
        <Route exact path="/" component={Home}/>
        <Route path="/about" component={About}/>
    </div>
</Router>

須要注意的是: <Router> 下只容許存在一個子元素,如存在多個則會報錯。因此在上面的代碼中,須要使用  <div></div> 將其餘元素包裹起來。

在實際的項目中,咱們通常不會直接使用 <Router>  ,而是使用以下所示的更高級的路由。在這裏將會介紹到第一個問題中用到的  <BrowserRouter>  以及其餘經常使用的高級路由。咳咳,集中精力了哈,重頭戲來了!

 <BrowserRouter>

使用 HTML5 提供的 history API (  pushState  ,  replaceState  和  popstate  事件) 來保持 UI 和 url 的同步。下面介紹一下該路由組件中的 5 個屬性:

  • basename: string

當前位置的基準 url 。若是你的頁面部署在服務器的二級(子)目錄,你須要將  basename 設置到此子目錄。 正確的 url 格式是前面有一個前導斜槓,但不能有尾部斜槓。

<BrowserRouter basename="/calendar"/>
<Link to="/today"/> // 渲染爲 <a href="/calendar/today">
  • getUserConfirmation: func

當導航須要確認時執行的函數。默認使用  window.confirm  。

// 使用默認的確認函數
const getConfirmation = (message, callback) => {
  const allowTransition = window.confirm(message)
  callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation}/>
  • forceRefresh: bool

當設置爲 true 時,在導航的過程當中整個頁面將會刷新。 只有當瀏覽器不支持 HTML5 的 history API 時,才設置爲 true 。

const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory}/>
  • keyLength: number

location.key 的長度,默認是 6。點擊同一個連接時,每次該路由下的 location.key 都會改變,能夠經過 key 的變化來刷新頁面。

<BrowserRouter keyLength={12}/>
  • children: node

渲染單一子組件(元素)。

 <HashRouter>

HashRouter 是一種特定的 <Router> , HashRouter 使用 url 的 hash (例如: window.location.hash ) 來保持 UI 和 url 的同步。因爲使用  hash  的方式記錄導航歷史不支持 location.key  和  location.state ,該技術僅用於支持傳統的瀏覽器,此 API 再也不贅述。

這兩個是常用的,剩下的還有  <MemoryRouter> 、<NativeRouter> 、 <StaticRouter>,有興趣的同窗能夠本身瞭解一下。

介紹完  <Router>,固然也要說下  <Route> ,咱們使用最頻繁的組件,主要職責是當頁面的訪問地址與  Route 上的  path  匹配時渲染出對應的 UI 界面。

<Route>  屬性值主要有:

  • path: string

能夠被 path-to-regexp 解析的有效 url 路徑。若是沒有 path,路由將老是被匹配。

<Route path="/users/:id" component={User}/>
  • exact: bool

爲 true 時,則要求路徑與  location.pathname  必須徹底匹配。經過下表解釋一下:

  •  strict: bool

爲  true 時,有結尾斜線的路徑只能匹配有斜線的  location.pathname  。見下表:

第二個屬性值  exact  就是咱們用來解決多個模塊同時渲染問題的,默認值爲 true 。

在這裏簡要提下  <Route>  渲染的三種方法:

  • <Route component> 當訪問地址和路由匹配時,一個 React component 將會被渲染
  • <Route render>  此方法適用於內聯渲染,並且不會產生重複裝載問題
  • <Route children>

當須要判斷訪問地址與路由是否匹配時,可使用此方法。當不匹配時, match 爲 null。

咱們上面代碼示例中使用的是第一種方法  <Route component>,這三種渲染方法都會用到  match 、location 、 history 這些屬性值。這裏再也不詳細介紹,使用時能夠查閱官方文檔。

須要注意的是 :每一種渲染方法都有其適用背景, <Route component>  的優先級比  <Route render>  高,而他們又都優先於  <Route children>  ,因此在同一個  <Route>  應該只使用一種方法,咱們大多數使用的是 component 方法。

說完第一種解決方法的原理,來剖析下第二種方法: <Switch> 。

該組件只渲染第一個與當前訪問地址匹配的  <Route>  或  <Redirect>  。它和多個堆疊的  <Route> 組件之間的區別是: <Switch>  只渲染一個路由。

在解決方法 (2)中,當咱們訪問  /card  , <Switch>  將會開始尋找與之匹配的路由,查找到  <Route path="/card"/>  匹配後,<Switch>  將會中止尋找而後開始渲染  /card 。<Switch>

  •  children: node

<Switch> 下的子節點只能是 <Route> 或 <Redirect> 元素且只有與當前訪問地址匹配的第一個子節點纔會被渲染。

3. 如何定義默認訪問頁面

當用戶手動修改 url 時,有時咱們須要定義一個默認頁面,從新引導用戶的操做,這個該如何實現呢?

使用 <Redirect> 。好比當用戶手動輸入 /test 以後,咱們須要跳轉至首頁,則代碼以下所示:

ReactDOM.render((
    <BrowserRouter>
        <div className="container">
            <Switch>
                <Route path={routePaths.INDEX} exact component={Index} />
                <Route path={routePaths.CARD} component={Card} />
                <Redirect to="/" />
            </Switch>
        </div>
    </BrowserRouter>
    ),
    document.getElementById('app')
);

方法解析:<Redirect> 渲染時將會導向一個新的地址,這個新的地址將會覆蓋掉 history 堆棧中的當前地址。

其經常使用的屬性是:

  • to: string

重定向的 url 地址。

<Redirect to="/somewhere/else"/>
  • to: object

重定向的 location 對象。

<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>
  • push: bool

取值爲 true 時,重定向操做將會把新地址加入到訪問的歷史記錄裏面,並不會替換掉當前的地址。

<Redirect push to="/somewhere/else"/>
  • from: string

須要匹配的將要被重定向的路徑。

<Switch>
  <Redirect from='/old-path' to='/new-path'/>
  <Route path='/new-path' component={Place}/>
</Switch>

須要注意的是:<Route> 元素使用 path 屬性進行匹配,<Redirect> 元素使用 from 屬性進行匹配。若是元素中沒有對應的 path 或 from,那麼它們將匹配任何當前的訪問地址。

4. 路由激活狀態的控制

相信你們對於 <link> 組件都不陌生,在 3.x 中,當須要將當前點擊的理由置爲激活狀態時,咱們能夠這樣設置:

//經過Style進行配置
<li><Link to="/home" activeStyle={{ color: 'red' }}>Home</Link></li>

//經過類名進行設置
<li><Link to="/home" activeClassName="active">Home</Link></li>

可是,通常狀況下只有主導航的連接才須要知道本身是否被激活。所以須要對主導航的 <Link>進行一層包裝,這樣就沒必要記得哪些地方有 activeClassName 或 activeStyle 。所謂的對 <Link> 包裝就是自定義 <Link> 組件,經過自定義實現特別的 Style 。在 3.x 中,具體實現方法以下:

// modules/NavLink.js
import React from 'react';
import { Link } from 'react-router';

export default class NavLink extends React.Component({
    constructor(props) {
        super(props);
    }

    render() {
        return <Link {...this.props} activeClassName="active"/>
    }
})
//使用方法:
import NavLink from './NavLink'
// ...
<li><NavLink to="/home">Home</NavLink></li>

可是,在 4.x 中咱們不須要作這些包裝工做,由於它直接提供了 <NavLink> 組件供咱們使用。使用方法:

<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>

下面對 <NavLink> 作下簡單介紹:

該組件是 <Link> 的特殊版本,當遇到匹配的 URL 渲染元素時會添加樣式屬性,適用於頁面導航部分。

  • activeClassName: string

導航選中時的樣式名,默認樣式名爲 active

<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>
  • activeStyle: object

導航選中時的樣式。

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

若值爲 true,當訪問地址嚴格匹配時激活樣式纔會生效。

<NavLink
  exact
  to="/profile"
>Profile</NavLink>
  • strict: bool

若值爲 true,只有當訪問地址後綴斜槓嚴格匹配(有或無)時激活樣式纔會生效。

<NavLink
  strict
  to="/events/"
>Events</NavLink>
  • isActive: func

用於添加頁面激活時的操做邏輯。

const oddEvent = (match, location) => {
  if (!match) {
    return false
  }
  const eventID = parseInt(match.params.eventID)
  return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink
  to="/events/123"
  isActive={oddEvent}
>Event 123</NavLink>

以上是 <NavLink> 組件的屬性介紹,供你們學習。

5. 頁面跳轉

在 3.x 中,跳轉頁面可使用如下方式:

import { browserHistory } from 'react-router';
//第一種方法
browserHistory.push('/some/path');
//第二種方法
this.context.router.push('/some/path');
//第三種方法
<Link to="'/some/path'"></Link>

在 4.x 中使用 push 方法跳轉頁面時,若是按照上面的寫法,頁面會報錯:

  

針對該問題有如下兩種解決方法:

(1)使用 history 控制路由的跳轉
this.props.history.push('/some/path');

簡單介紹下 history

history 指的是 history 包,是 4.x 中的重要依賴之一。常見的 history 路由方案有三種形式,分別是:

  • browser history  在 DOM 上的實現,用於支持 HTML5 history API 的瀏覽器;
  • hash history  在 DOM 上的實現,用於舊版瀏覽器;
  • memory history  在內存上的實現,用於測試或非 DOM 環境(如 React Native)。

history 對象包含的屬性和方法以下所示:

  • length: number history 堆棧中的地址數目
  • action: string 當前的動做 (PUSH , REPLACE , 或者是 POP )
  • location: object 當前訪問地址信息組成的對象
  • push(path, [state]): func 在 history 堆棧信息里加入一個新路徑
  • replace(path, [state]) : func 替換 history 堆棧信息裏的當前路徑
  • go(n) : func 將 history 堆棧中的指針向前移動 n
  • goBack(): func 等同於 go(-1)
  • goForward(): func 等同於 go(1)
  • block(prompt) : func 阻止跳轉

須要注意的是:history 對象是可變的,因此不要從 history.location 直接獲取,而是須要經過 <Route> 的prop 來獲取 location

(2)使用 Context,得到 router 對象
import React from "react";
import PropTypes from "prop-types";

class MyComponent extends React.Component {
  static contextTypes = {
    router: PropTypes.object
  }
  constructor(props, context) {
     super(props, context);
  }
  ...
  myFunction() {
    this.context.router.history.push("/some/Path");
  }
  ...
}

以上兩種方法中推薦使用第一種,由於 React 不推薦使用 context , 在將來版本中有可能被拋棄哦。

6. 切換路由後,頁面仍然停留在上一個頁面的位置

由 A 頁面跳轉到 B 頁面,B 頁面停留在 A 頁面的位置,沒有返回到頂部。

問題分析:在 React Router 早期版本中你們可使用滾動恢復的開箱即用功能,可是在 4.x 中路由切換時並不會恢復滾動位置,用戶須要對 window 和獨立組件的滾動位置進行管理。可使用 withRouter 組件: withRouter 能夠訪問歷史對象的屬性和最近的 <Route> 匹配項,當路由的屬性值 { matchlocationhistory } 改變時,withRouter 都會從新渲染。該組件能夠攜帶組件的路由信息,避免組件之間一層層傳遞。使用方法以下:

withRouter(MyComponent)

這樣就能夠獲取到 MyComponent 組件的路由信息了。

解決方法:使用 withRouter 封裝 ScrollToTop 組件。這裏就用到了 withRouter 攜帶路由信息的特性,經過對比props 中 location 的變化,實現頁面的滾動。

(1)定義 ScrollToTop 組件,代碼以下:
import React, { Component } from 'react';
import { Route, withRouter } from 'react-router-dom';
class ScrollToTop extends Component {
    componentDidUpdate(prevProps) {
        if (this.props.location !== prevProps.location) {
          window.scrollTo(0, 0)
        }
    }
    render() {
        return this.props.children
    }
}

export default withRouter(ScrollToTop);
(2)在定義路由處引用該組件,例如:
ReactDOM.render((
    <BrowserRouter>
        <ScrollToTop>
            <div className="container">
                <Route path={routePaths.INDEX} exact component={Index} />
                <Route path={routePaths.CARD} component={Card} />
            </div>
        </ScrollToTop>
    </BrowserRouter>
    ),
    document.getElementById('app')
);

這樣處理以後,當跳轉頁面時都會自動回到該頁面的頂部位置。

7. 頁面之間如何傳值?

問題背景:當路由發生跳轉時咱們可能須要攜帶一些參數。

解決方法:使用 props 屬性,介紹如下三種傳值方法:

(1)props.params

指定一個 path ,而後指定通配符能夠攜帶參數到指定的 path :

<Route path='/user/:name' component={UserPage}></Route>

跳轉 UserPage 頁面時,能夠這樣寫:

//link方法
<Link to="/user/sam">用戶</Link>
//push方法
this.props.history.push("/user/sam");

在 UserPage 頁面中經過 this.props.params.name 獲取值。

上面的方法能夠傳遞一個或多個值,可是每一個值的類型都是字符串,無法傳遞一個對象。若是要傳的話能夠將 json 對象轉換爲字符串,傳遞過去以後再將 json 字符串轉換爲對象。

let data = {id:3,name:sam,age:36};
data = JSON.stringify(data);
let path = '/user/${data}';

//在頁面中獲取值時
let data = JSON.parse(this.props.params.data);
(2)query

query 方式能夠傳遞任意類型的值,可是頁面的 url 也是由 query 的值拼接的,url 很長且是明文傳輸。

//定義路由
<Route path='/user' component={UserPage}></Route>

//數據定義
let data = {id:3,name:sam,age:36};
let path = {
    pathname: '/user',
    query: data,
}

//頁面跳轉
<Link to={path}>用戶</Link>
this.props.history.push(path);

//頁面取值
let data = this.props.location.query;
let {id,name,age} = data;
(3)state

state 方式相似於 post,依然能夠傳遞任意類型的數據,並且能夠不以明文方式傳輸。

//定義路由
<Route path='/user' component={UserPage}></Route>

//數據定義
let data = {id:3,name:sam,age:36};
let path = {
    pathname: '/user',
    state: data,
}

//頁面跳轉
<Link to={path}>用戶</Link>
this.props.history.push(path);

//頁面取值
let data = this.props.location.state;
let {id,name,age} = data;

在實際的項目開發中,你們能夠根據項目須要選擇合適的傳值方法。

8. 使用 <BrowserRouter> 配置路由,上傳頁面至服務器後頁面出現 404

問題背景:項目中控制路由跳轉使用的是 <BrowserRouter>,代碼以下:

ReactDOM.render((
    <BrowserRouter>
        <div className="container">
            <Route path={routePaths.INDEX} exact component={Index} />
            <Route path={routePaths.CARD} component={Card} />
        </div>
    </BrowserRouter>
    ),
    document.getElementById('app')
);

在開發過程當中使用是沒有問題的,可是將頁面上傳至服務器以後,問題就來了:用戶訪問的資源不存在,頁面是空白的。

問題分析:<BrowserRouter> 是使用 React-Router 應用推薦的 history 方案。它使用瀏覽器中的 History API 用於處理 url,建立一個像 example.com/list/123 這樣真實的 url。當經過真實 url 訪問網站的時候,因爲路徑是指向服務器的真實路徑,但該路徑下並無相關資源,因此用戶訪問的資源不存在。

解決方法:

(1)使用 <HashRouter>

它使用 url 中的 hash(#)部分去建立路由,舉例來講,用戶訪問 http://www.example.com/ ,實際會看到的是 http://www.example.com/#/ 。
爲何本地開發時沒有問題呢?那是由於咱們的 React 腳手架中使用 webpack-dev-server 作了配置。

webpackConfig.devServer = {
    disableHostCheck: true,
    contentBase: path.resolve(__dirname, 'build'),
    compress: true, //gzip壓縮
    historyApiFallback: true
};
(2)若是要使用 <BrowserRouter> 的話,服務器須要進行相關路由配置,方法見擴展閱讀 [1]。

9. React Router 4.x 如何配置按需加載?

問題背景:當訪問首頁時會一次性請求全部的 js 資源,這會大大影響頁面的加載速度和用戶體驗。因此添加按需加載功能是必要的。

問題分析:4.x 官網中推薦使用 bundle loader 實現代碼拆分,因此咱們選擇使用 bundle loader 。

解決方法:配置按需加載的步驟以下:

(1)安裝 bundle-loader
npm install --save-dev bundle-loader
(2)定義 Bundle.js

<Bundle> 組件會接受一個名爲 load 的 props, load 是一個組件異步加載的方法,該方法須要傳入一個回調函數做爲參數,而後回調函數會在方法內異步接收加載完的組件,詳細代碼以下:

import React, { Component } from 'react';
export default class Bundle extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            // short for "module" but that's a keyword in js, so "mod"
            mod: null
        }
    }

    componentWillMount() {
        this.load(this.props)
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.load !== this.props.load) {
            this.load(nextProps)
        }
    }

    load(props) {
        this.setState({
            mod: null
        })
        props.load((mod) => {
            this.setState({
                // handle both es imports and cjs
                mod: mod.default ? mod.default : mod
            })
        })
    }

    render() {
        if (!this.state.mod)
            return false
        return this.props.children(this.state.mod)
    }
}
(3)入口文件 app.jsx 配置。

使用 bundle-loader 爲每一個頁面組件配置按需加載,默認打開的首頁能夠直接引入,不須要使用 <Bundle> 組件進行處理,代碼以下所示:

import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter, Route } from 'react-router-dom';
import * as routePaths from './js/constants/routePaths';
import Bundle from './js/constants/Bundle.js';
//默認打開頁面直接引入
import Index from './js/pages/Index';
//其餘頁面異步引入
import CardContainer from 'bundle-loader?lazy&name=app-[name]!./js/pages/Card';
import './assets/css/index.scss';

const Card = () => (
    <Bundle load={CardContainer}>
        {(Card) => <Card />}
    </Bundle>
)

ReactDOM.render((
    <HashRouter>
        <div className="container">
            <Route path={routePaths.INDEX} exact component={Index} />
            <Route path='/card' component={Card} />
        </div>
    </HashRouter>
    ),
    document.getElementById('app')
);
(4)webpack.config.js 修改,配置子文件名稱。
webpackConfig.output = {
    path: path.resolve(__dirname, 'build/' + config.ftpTarget),
    publicPath: config.publicPath + '/',
    filename: 'js/[name].js',
    chunkFilename: 'js/[id].js'
}

這樣配置以後,打包出來的 js 文件已經進行了拆分,每一個頁面對應一個本身的 js ,當訪問該頁面時才加載相應的資源。

10. this.props.history.push() 進行路由跳轉時報錯

問題背景:配置按需加載後,首頁能夠正常跳轉子頁面,而在子頁面中進行頁面跳轉時出現報錯:this.props.history.push中'push'is undefined 。

問題分析:項目中使用 this.props.history.push() 方法實現路由跳轉,未進行文件拆分時能夠正常使用,可是當進行文件拆分以後,子文件中沒法獲取 this.props.history 對象。

解決方法:使用 withRouter 封裝頁面組件。示例代碼以下:

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

class Card extends React.Component {
  constructor(props) {
      super(props);

    }
    render() {
      return (
        <div className="wrapper">
          <p>這是第二頁:測試</p>
      </div>
      );
    }
}
export default withRouter(Card);

這樣封裝以後,就無需一級級傳遞 React Router 的屬性,子文件內也能夠拿到須要的路由信息。

以上列出的內容就是咱們在使用 4.x 開發時遇到的一些問題,針對每一個問題不只給出瞭解決方法,還介紹瞭解決方法中涉及到的知識點。對於一些未介紹到的內容,你們能夠移步官網進行深度學習(見擴展閱讀 [2])。

小結

對於新項目來講,使用 React Router 4.x 進行開發是一個不錯的選擇。由於其組件化的思想和 React 很像,學習起來比較容易、上手快。除了官網 [2] ,擴展閱讀中咱們還給出了 React Router 4.x 的其餘學習文檔 [3][4],供你們參考。值得注意的是,上述問題解決方法中的示例代碼使用的是 React v16 版本,在實際使用時須要結合本身的環境進行適當修改。

React Router 4.x 這次帶來的改變是顛覆性的,對於咱們使用者來講是一種挑戰,同時也是一種知識的有趣探索。組件化路由設計理念和動態路由的配置給咱們的項目開發帶來了更大的靈活性。文中在介紹問題解決方法時對一些 4.x 的 API 作了簡要的介紹,對於一些更細節化的東西,須要咱們移步官網進行深刻的學習,而後再慢慢的探索。React Router 的做者說過版本號要永遠和 React 保持一致,因此相信咱們的 React Router 探索之旅將會一直進行着……同志們,Hold On!

好了,關於 React Router 4.x 開發實踐中遇到的問題就介紹到這裏了,若有任何疑問,歡迎留言。

擴展閱讀

[1] https://www.thinktxt.com/react/2017/02/26/react-router-browserHistory-refresh-404-solution.html

[2] http://reacttraining.cn/

[3] https://github.com/ReactTraining/react-router

[4] https://www.sitepoint.com/react-router-v4-complete-guide/

有興趣歡迎關注咱們的公衆號:全棧探索。歡迎交流。

相關文章
相關標籤/搜索