版本区别
react-router 4之后的版本和之前的版本差别真的很大
嵌套路由
v3中的嵌套路由通常书写如下,路由集中写在一起
import { Router, Route, IndexRoute } from 'react-router'
const PrimaryLayout = props => (
<div className="primary-layout">
<header>
Our React Router 3 App
</header>
<main>
{props.children}
</main>
</div>
)
const HomePage =() => <div>Home Page</div>
const UsersPage = () => <div>Users Page</div>
const App = () => (
<Router history={browserHistory}>
<Route path="/" component={PrimaryLayout}>
<IndexRoute component={HomePage} />
<Route path="/users" component={UsersPage} />
</Route>
</Router>
)
render(<App />, document.getElementById('root'))
以下是v3中的一些关键概念,这些概念在v4中不再适用:
- 路由器集中在一个地方。
- 布局和页面嵌套是通过嵌套<Route>组件派生的。
- 布局和页面组件完全天真,因为它们是路由器的一部分。
React Router 4不再提倡集中式路由器。相反,路由规则存在于布局内以及UI本身之间。这里是v4中的相同应用程序:
import { BrowserRouter, Route } from 'react-router-dom'
const PrimaryLayout = () => (
<div className="primary-layout">
<header>
Our React Router 4 App
</header>
<main>
<Route path="/" exact component={HomePage} />
<Route path="/users" component={UsersPage} />
</main>
</div>
)
const HomePage =() => <div>Home Page</div>
const UsersPage = () => <div>Users Page</div>
const App = () => (
<BrowserRouter>
<PrimaryLayout />
</BrowserRouter>
)
render(<App />, document.getElementById('root'))
exact
v4以后的版本,路由匹配默任情况下,在匹配到了符合条件的路由后,并不会停止匹配,而是会继续匹配符合条件的路由。
exact是Route的一个属性,认为其是一种严格匹配模式
- 当exact为false时,根据路由匹配所有组件,如"/" 匹配 “/”、“/home”、“/home/menu,“/home”则会匹配“/”、“/home/menu;
- 当exact为true时,则“/” 仅匹配“/”、无法匹配到“/home”。
<Route path='/' component={Home} />
<Route path='/page' component={Page}>
//这种情况下,如果匹配路由path='/page',那么会把Home也会展示出来。
//既路由path='/page'会匹配路由path='/'和路由path='/page'
<Route exact path='/' component={Home} />
<Route path='/page' component={Page} />
//这样匹配路由path='/page',只会匹配到Page组件
该属性主要解决父路由和子路由之间的问题。
Switch
如果只需要一个满足匹配要求的组件,则使用<Switch>路由,它会在匹配到第一个适合的卢友初停住。
<Switch>
<Route path="/" exact component={HomePage} />
<Route path="/users/add" component={UserAddPage} />
<Route path="/users" component={UsersPage} />
<Redirect to="/" />
</Switch>
上例在输入"/users"或者"/users/add"时,最终都会只渲染{UserAddPage}。如果在给"/users/add"添加exact,则输入"/users"只会匹配"/users","/users/add"只会匹配"/users/add"。
Redirect
如果没有解析路由,则使用<Switch>和<Redirect>重定向到具有有效路径的默认页面,甚至是未找到的页面(自己定义的404页面)。<Redirect>一般放在最后面。
例如在下例中,如果<Redirect>之上的路由全部没有匹配到,则会重定向到定义的NotFound页面。
<Switch>
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<Route path="/order/detail/:orderId" component={OrderMap} />
<Route path="/admin" component={Admin} />
<Route path="/error" component={NotFound}/>
<Redirect to="/error" />
</Switch>
以下写法能实现与上例相同的效果,优点是在<Switch>中不用定义NotFound页面的路由。缺点是在其它地方需要跳转到NotFound页面时,还是需要再次定义NotFound的路由。
<Switch>
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<Route path="/order/detail/:orderId" component={OrderMap} />
<Route path="/admin" component={Admin} />
<Route component={NotFound}/>
</Switch>
withRouter
如果一个组件没有被<Route>包裹,则它无法使用this.props.history.push进行路由的跳转。withRouter的作用就是将一个组件包裹进Route里面, 然后react-router的三个对象history, location, match就会被放进这个组件的props属性中.
// withRouter实现原理:
// 将组件包裹进 Route, 然后返回
const withRouter = () => {
return () => {
return <Route component={Nav} />
}
}
// 这里是简化版
const withRouter = ( Component ) => () => <Route component={ Component }/>
实际项目中,直接使用修饰器@withRouter写在class之前,如下所示。
@withRouter
class AuthRouter extends Component {
// code
}
实际体验
业务需求
设置一个登陆界面、注册界面、用户界面的路由。在用户界面,导航栏和头部、尾部的组件是通用的,内容组件需要设置路由来达到切换。其它路由重定向到404界面。
登录.PNG 用户界面.PNG代码分析
主要用到了嵌套路由、Switch和Redirect。在index界面的路由设置如下,首先通过<AuthRouter>组件判断用户登录信息,不满足登录情况,则会通过this.props.history.push()跳转到Login页面;满足登录条件则会去<Switch>里面匹配路由,若未匹配到路由,则重定向到404页面。
<div>
<BrowserRouter>
<AuthRouter></AuthRouter>
<Switch>
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<Route path="/order/detail/:orderId" component={OrderMap} />
<Route path="/admin" component={Admin} />
{/* <Route component={NotFound}/> */}
<Route path="/error" component={NotFound}/>
<Redirect to="/error" />
</Switch>
</BrowserRouter>
</div>
若匹配到了admin页面,则会进入到<Admin>组件中去继续匹配对应的子组件,匹配过程与上面相似,<Admin>组件的渲染代码如下
<Row className='container'>
<Col span='4' className='navi-left'>
<NaviLeft />
</Col>
<Col span='20' className='main'>
<Header className='header' history={this.props.history}/>
<Row className='content'>
<Switch>
<Route path='/admin/home' component={Home} />
<Route path='/admin/city' component={City} />
<Route path='/admin/order' component={Order} />
<Route path='/admin/user' component={User} />
<Route path='/admin/Map' component={bikeMap} />
<Route path='/admin/charts/bar' component={Bar} />
<Route path='/admin/charts/line' component={Line} />
<Route path='/admin/charts/pie' component={Pie} />
<Route path='/admin/permission' component={Permission} />
<Route component={NotFound}/>
{/* <Redirect to="/error"></Redirect> */}
</Switch>
</Row>
<Footer className='footer'/>
</Col>
</Row>
网友评论