React-Router Route 路由组件

Route 组件主要的作用就是当一个 location 匹配路由的 path 时,渲染指定的 UIReact-Route 的核心就是 Route

1
2
3
4
5
6
7
8
import { BrowserRouter as Router, Route } from 'react-router-dom'
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/news" component={NewsFeed}/>
</div>
</Router>

如果应用的地址是 /,那么相应的UI会类似这个样子:

1
2
3
4
<div>
<Home/>
<!-- react-empty: 2 -->
</div>

如果应用的地址是 /news,那么相应的UI就会成为这个样子:

1
2
3
4
<div>
<!-- react-empty: 1 -->
<NewsFeed/>
</div>

react-empty 注释演示了 React 渲染 null 的细节。其实 Route 就算是 null 也会被渲染,只要地址与路由的路径匹配,组件就会渲染。

Route#render

使用 Route 有三种渲染内容的方法:

  • component
  • render
  • children

在不同的情况下每个都特别有用,对于某个 Route,只能使用这些 props 中的一个,绝大多数的时候会使用 component

Route props

这三种渲染方法都会获得相同的三个的属性:

  • match
  • location
  • history

component

只有在地址匹配的时候 React 的组件才会被渲染,route props 也会随着一起被渲染。

如果你使用 component 渲染内容的方法而不是使用 render,路由会根据指定的组件使用React.createElement 来创建一个新的 React element。这就意味着如果你提供的是一个内联的函数的话会带来很多意料之外的重新挂载。所以,对于内联渲染,要使用 render 属性。

render: func

render 方式对于内联渲染和包装组件却不引起意料之外的重新挂载特别方便。使用 render 属性,可以选择传一个在地址匹配时被调用的函数,而不是像使用 component 属性那样得到一个新创建的 React element。使用 render 属性会获得跟使用 component 属性一样的 route props

1
2
3
4
5
6
7
8
9
10
11
12
13
// 便捷的行内渲染
<Route path="/home" render={() => <div>Home</div>}/>
// 包装/合成
const FadingRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
<FadeIn>
<Component {...props}/>
</FadeIn>
)}/>
)
<FadingRoute path="/cool" component={SomeComponent}/>

注意: Route component 的优先级要比 Route render 高,所以不要在同一个 Route 中同时使用这两个属性。

children: func

有时候可能想不管地址是否匹配都渲染一些内容,这种情况可以使用 children 属性。它与 render 属性的工作方式基本一样,不同的是不管地址匹配与否 children 都会被调用。除了在路径不匹配 URLmatch 的值为 null 之外,children 渲染属性会获得与 componentrender 一样的 route props。这就允许你根据是否匹配路由来动态地调整 UI,来看这个例子,如果路由匹配的话就添加一个 active 类:

1
2
3
4
5
6
7
8
9
10
11
12
<ul>
<ListItemLink to="/somewhere"/>
<ListItemLink to="/somewhere-else"/>
</ul>
const ListItemLink = ({ to, ...rest }) => (
<Route path={to} children={({ match }) => (
<li className={match ? 'active' : ''}>
<Link to={to} {...rest}/>
</li>
)}/>
)

甚至可以直接在 children 里面返回一个组件:

1
2
3
4
5
6
7
8
const ListItemLink = ({ ...rest }) => (
<Route {...rest} children={({ match }) => {
console.log(match);
return <About />
}}/>
)
// ...
<ListItemLink path="/about"/>

这种属性对于动画也特别有用:

1
2
3
4
5
6
7
<Route children={({ match, ...rest }) => (
{/* Animate总会被渲染, 所以你可以使用生命周期来使它的子组件出现或者隐藏
*/}
<Animate>
{match && <Something {...rest}/>}
</Animate>
)}/>

Route componentRoute render 的优先级都比 Route children 高,所以在同一个 Route 中不要同时使用一个以上的属性.

path: string

可以是任何 path-to-regexp 能理解的有效 URL

没有 path 属性的 Route 总是会匹配。

exact: bool

当值为true时,则要求路径与 location.pathname 必须 完全匹配

strict: bool

当设为true的时候,有结尾斜线的路径只能匹配有斜线的 location.pathname,这个值并不会对 location.pathname 中有其他的片段有影响。

1
<Route strict path="/one/" component={About}/>

路径 location.pathname 是否匹配?


  • /one/ /one 否
  • /one/ /one/ 是
  • /one/ /one/two 是

警告: strict 可以强制 location.pathname 不包含结尾的斜线,但是要做到这点必须把 strictexect 都设置为true。

1
<Route exact strict path="/one" component={About}/>

路径 location.pathname 是否匹配?

  • /one /one 是
  • /one /one/ 否
  • /one /one/two 否