1. 程式人生 > >react(ant-design-pro)路由-router踩坑

react(ant-design-pro)路由-router踩坑

最近學習react,使用的是阿里推出的ant-design-pro框架,踩了一些關於react(ant-design)路由的坑,在此做一下總結。

router

我們先大致瞭解一下react和ant-design-pro中的路由。

首先我們來講一下React中原生的路由(router)的實現方式:

是以路由標籤巢狀的形式,把路徑(path)和對應要渲染的元件(component)以屬性的形式指定在路由標籤中,即可配置好路由。

React.render((
  <Router>
    <Route path="/" component={App}>
      {/* 當 url 為/時渲染 Dashboard */}
      <IndexRoute component={Dashboard} />
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox}>
        <Route path="messages/:id" component={Message} />
      </Route>
    </Route>
  </Router>
), document.body)

然後再看ant-design-pro中的路由:

const routerConfig = {
    '/': {
      component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
    },
    '/dashboard/analysis': {
      component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')),
    },
    '/dashboard/monitor': {
      component: dynamicWrapper(app, ['monitor'], () => import('../routes/Dashboard/Monitor')),
    },
}

ant-design-pro把路由配置這個過程封裝了一遍,我們需要做的就是在src/common/router.js檔案下,寫一份如上程式碼的路由配置資料,ant-design-pro會把這些配置資訊轉化成react原生的路由標籤,從而實現路由。

ant-design-pro中寫路由配置資料的問題

antd-pro的對路由配置資料有一個模糊檢索的機制,通常我們寫一個類似於/dashboard/analysis的路徑,毫無疑問,我們在瀏覽器開啟 */dashboard/analysis 可以正常訪問到該路徑對應的路由;但如果我們輸入了一個沒有在路由中定義的、此路徑的子路徑,antd會先查詢該路徑,沒有查詢到就會向上路徑匹配,即*/dashboard/analysis 。也就是說,如果我們在路由配置中寫的是 */dashboard/analysis,且我們在瀏覽器開啟的路徑是 */dashboard/analysis/test,但是實際效果是隻會顯示*/dashboard/analysis 路徑對應的頁面。

同時這個機制還有一個副作用:

當定義的路由是*/dashboard/analysis,沒有以"/"結尾,antd的路由機制會始終認為 */dashboard/analysis是最末端的路徑,即我們再到路由中定義一個*/dashboard/analysis/page1,然後我們到瀏覽器去訪問 */dashboard/analysis/page1,它會因為上述機制,始終會指向 */dashboard/analysis這個路徑。也就是說,我們要想在某個路徑中繼續寫它的子路徑,我們必須以"/"結尾,形如 */dashboard/analysis/ ,否則會因為antd-pro的這個機制,不渲染其子路由。

路由的跳轉

pathname、history

關於路由的跳轉問題,普遍是以 <Link>標籤,和事件觸發 兩種方式來進行的:

Link標籤: <Link to={{ pathname : ' /sort ' , query : { name : 'sunny' }}}> 點選跳轉 </Link> 

事件:this.props.history.push({ pathname : '/sort' ,query : { name: ' sunny'} })

值得注意的是,我在網上看到的資料,pathname這個屬性名寫的是path,但是經過我的測試發現使用path並不能實現跳轉,還會報錯:Warning: Hash history cannot PUSH the same path; a new entry will not be added to the history stack

而用pathname就可以解決這個問題;

其次,使用事件觸發的方式,要使用this.props.history.push,而網上的很多說法是寫this.props.router.push,這樣寫會報錯:router為undefined。

withRouter

在摸索react路由的過程中,還碰到一個問題:在子元件中想要觸發跳轉事件時,我按上述的history寫了一個點選事件,點選後執行this.props.history.push({pathname:'/xxx'}),但是出現了報錯,說history未定義。在網上搜索後找到了一個合適的解決方法:

先在子元件中引入withRouter: import { withRouter } from "react-router-dom";

然後在子元件export匯出時,用withRouter將組建包裹起來: withRouter(ChildComponent)

這樣即可使得子元件的props屬性也帶上了history方法。

路由的傳參、取參

Params

第一種形式是將引數直接掛在url的後面,用"/"隔開,但是我們再定義路由之前就要把這個引數約定好,形如 /sort/:id,這裡的id可以看做一個佔位符,當我們跳轉到形如 /sort/5的路徑時,我們會轉到引數id=5對應的頁面。

此時我們可以通過params來獲取引數。這個時候又碰到坑了:

網上的資料大多數是說通過this.props.params.id即可取到引數id的值,但是我實際操作過程中,顯示params為undefined。於是我把this.props在控制檯打印出來,看到其中包含了form,history,location,match,routerData,staticContext,逐個點開發現,我們需要的params竟然在match裡面!

也就是說,要取得路由形式為/sort/:id的引數,實際上是通過 this.props.match.params.id取到的,關於這個問題被很多網上的答案誤導了。

query

第二種傳參形式就是在寫跳轉連結的時候,將路徑和引數以物件的形式寫在一起,如:{ pathname : '/sort' ,query : { name: ' sunny'}}。

這樣的形式傳遞的引數,是不會顯示在url中的,並且在重新整理頁面的時候,引數會丟失,(類似於post傳參)。

當我們第一次跳轉到*/sort頁面的時候,可以通過  this.props.location.query  取到query中輸入的引數。

值得注意的是,經過我的測試後發現,query這個鍵名可以任意命名,例如"aaa",之後在跳轉到的頁面通過 this.props.location.aaa也可以獲取到引數。