React Router從V2/V3到V4的變化

八叉樹發表於2019-01-06

React Router v4幾乎重寫了v2/v3,相比於v3變化較大,包括Router/Route的改變,元件巢狀的方式,路由的生命週期,Swicth和Redirect等元件都改變較多,新版本的react router更偏向元件化,基本上與React的思想一致。

Router

在v3中,我們使用帶history屬性的Router

// v3
import routes from './routes'
<Router history={browserHistory} routes={routes} />
// or
<Router history={browserHistory}>
  <Route path='/' component={App}>
    // ...
  </Route>
</Router>
複製程式碼

在v4中,提供了幾種不同的Router元件,每個Router元件都會建立一個history物件。

//v4
<BrowserRouter>
  <div>
    <Route path="/about" component={About} />
    <Route path="/contact" component={Contact} />
  </div>
</BrowserRouter>
複製程式碼

在v3中Router元件裡面可以渲染多個元件

// V2 or V3
import { Router, Route, hashHistory } from 'react-router';

<Router history={hashHistory}>
  <Route path='/about' component={About} />
  <Route path='/contact' component={Contact} />
</Router>
複製程式碼

而v4中,Router元件只能渲染一個元件

// yes
<BrowserRouter>
  <div>
    <Route path='/about' component={About} />
    <Route path='/contact' component={Contact} />
  </div>
</BrowserRouter>

// no
<BrowserRouter>
  <Route path='/about' component={About} />
  <Route path='/contact' component={Contact} />
</BrowserRouter>
複製程式碼

Routes

在v3中,並不是一個元件,所有的只是建立一個route配置物件

/// in v3 the element
<Route path='contact' component={Contact} />
// was equivalent to
{
  path: 'contact',
  component: Contact
}
複製程式碼

在v4中,元件就是一個真正的元件,當path與當前location匹配時,就會使用rendering prop(component,render或者children)來渲染;當path沒有匹配到時,就會渲染null。

巢狀路由

在v3中,的巢狀通過將它們作為父的children

<Route path="parent" component={Parent}>
  <Route path="child" component={Child} />
  <Route path="other" component={Other} />
</Route>
複製程式碼

在v4中,只能被它的父元件渲染

<Route path="parent" component={Parent} />;

function Parent() {
  return (
    <div>
      <Route path="child" component={Child} />
      <Route path="other" component={Other} />
    </div>
  );
}
複製程式碼

路由的生命週期

V3提供了onEnteronUpdateonLeaves方法,在v4中我們需要用生命週期方法,用componentDidMount代替onEnter,用componentDidupdate代替onUpdate,用componentWillUnmount代替onLeave

Switch

在v3中,我們可以指定多個子routes,只有第一個匹配的才會渲染

// v3
<Route path="/" component={App}>
  <IndexRoute component={Home} />
  <Route path="about" component={About} />
  <Route path="contact" component={Contact} />
</Route>
複製程式碼

v4提供了元件,當一個元件被渲染時,只有匹配當前location的第一個child 才會被渲染。

// v4
const App = () => (
  <Switch>
    <Route exact path="/" component={Home} />
    <Route path="/about" component={About} />
    <Route path="/contact" component={Contact} />
  </Switch>
);
複製程式碼

Redirect

在v3中,如果我們需要進行路徑的跳轉,比如從/ 跳轉到/welcome,就需要用到IndexRedirect

// v3
<Route path="/" component={App}>
  <IndexRedirect to="/welcome" />
</Route>
複製程式碼

在V4中,我們可以使用 Redirect

// v4
<Route exact path="/" render={() => <Redirect to="/welcome" component={App} />} />

<Switch>
  <Route exact path="/" component={App} />
  <Route path="/login" component={Login} />
  <Redirect path="*" to="/" />
</Switch>
複製程式碼

在v3中,Redirect保留了查詢字串

// v3

<Redirect from="/" to="/welcome" />
// /?source=google → /welcome?source=google
複製程式碼

在v4中,我們需要重新傳遞這些屬性到 to屬性上

// v4

<Redirect from="/" to="/welcome" />
// /?source=google → /welcome

<Redirect from="/" to={{ ...location, pathname: "/welcome" }} />
// /?source=google → /welcome?source=google
複製程式碼

其他變化

history.push和history.replace

/ V2 or V3
history.push({
    pathname: '/home',
    query: {
        foo: 'test',
bar: 'temp'
    }
});
history.replace({
    pathname: '/home',
    query: {
        foo: 'test',
bar: 'temp'
    }
});


// V4
history.push({
    pathname: '/home',
    search: '?foo=test&bar=temp',
});
history.replace({
    pathname: '/home',
    search: '?foo=test&bar=temp',
});

複製程式碼

可選引數

在v3中通過括號來表示可選 path="/entity/:entityId(/:parentId)"

在v4中通過一個尾隨的問號來表示可選 path="/entity/:entityId/:parentId?"

props.params

// V2 or V3 獲取params可以這麼獲取
this.props.params
複製程式碼
// V4
this.props.match.params
複製程式碼

location.query(查詢字串)

V4 去掉了location.query,只能使用search來獲取,為了讓其跟瀏覽器一樣,如果想要相容以前的location.query,可以使用query-string庫解析一下

// V2 or V3 獲取query可以這麼獲取
this.props.location.query
複製程式碼
// V4 去掉了location.query,只能使用search來獲取,為了讓其跟瀏覽器一樣
// 如果想要相容以前的location.query,可以使用query-string庫解析一下
// 如: queryString.parse(props.location.search)
this.props.location.search
複製程式碼

location.action

// V2 or V3 獲取location的action
this.props.location.action
複製程式碼
// V4 去掉了location.action, 放在了history裡面
history.action
複製程式碼

獲取history庫

//以前獲取react-router裡面的history庫,可以這麼獲取:

import {hashHistory as history} from 'react-router';
複製程式碼
//V4

import createHashHistory as history from 'history/createHashHistory';
複製程式碼

參考文章:

Migrating from v2/v3 to v4

ReactRouter升級 v2 to v4

相關文章