<Router>
在 4.0 之前版本的 API 中,<Router> 组件的 children 只能是 React Router 提供的各种组件,如 <Route>、<IndexRoute>、<Redirect> 等。而在 React Router 4 中,你可以将各种组件及标签放进 <Router> 组件中,他的角色也更像是 Redux 中的 <Provider>。不同的是 <Provider> 是用来保持与 store 的更新,而 <Router> 是用来保持与 location 的同步。示例如下:
// 示例 1
<Router>
<div>
<ul>
<li><Link to="/"> 首页 </Link></li>
<li><Link to="/about"> 关于 </Link></li>
<li><Link to="/topics"> 主题列表 </Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
Router 是所有路由组件共用的底层接口,一般我们的应用并不会使用这个接口,而是使用高级的路由:
- <BrowserRouter>:使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步;
- <HashRouter>:使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和 URL 的同步;
- <MemoryRouter>:能在内存保存你“URL”的历史纪录(并没有对地址栏读写);
- <NativeRouter>:为使用 React Native 提供路由支持;
- <StaticRouter>:从不会改变地址;
注意:这里 <Router> 组件下 只允许存在一个子元素,如存在多个则会报错。
反面典型在这里:
// 示例 2 在没有 <div> 包裹下,会抛出异常信息
<Router>
<ul>
<li><Link to="/"> 首页 </Link></li>
<li><Link to="/about"> 关于 </Link></li>
<li><Link to="/topics"> 主题列表 </Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</Router>
<Route>
Route 组件主要的作用就是当一个 location 匹配路由的 path 时,渲染某些 UI。示例如下:
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/news" component={NewsFeed}/>
</div>
</Router>
// 如果应用的地址是 /, 那么相应的 UI 会类似这个样子:<div>
<Home/>
</div>
// 如果应用的地址是 /news, 那么相应的 UI 就会成为这个样子:<div>
<NewsFeed/>
</div>
<Route> 组件有如下属性:
- path(string): 路由匹配路径。(没有 path 属性的 Route 总是会匹配);
- exact(bool):为 true 时,则要求路径与 location.pathname 必须完全匹配;
- strict(bool):true 的时候,有结尾斜线的路径只能匹配有斜线的 location.pathname;
exact 配置:
路径 location.pathname exact 是否匹配
/one /one/two true 否
/one /one/two false 是
strict 配置:
路径 location.pathname strict 是否匹配
/one/ /one true 否
/one/ /one/ true 是
/one/ /one/two true 是
同时,新版的路由为 <Route> 提供了三种渲染内容的方法:
- <Route component>:在地址匹配的时候 React 的组件才会被渲染,route props 也会随着一起被渲染;
- <Route render>:这种方式对于内联渲染和包装组件却不引起意料之外的重新挂载特别方便;
- <Route children>:与 render 属性的工作方式基本一样,除了它是不管地址匹配与否都会被调用;
第一种和之前一样,这里我们重点看下 <Route render> 的渲染方式:
// 行内渲染示例
<Route path="/home" render={() => <div>Home</div>}/>
// 包装 / 合成
const FadingRoute = ({component: Component, ...rest}) => (<Route {...rest} render={props => (
<FadeIn>
<Component {...props}/>
</FadeIn>
)}/>
)
<FadingRoute path="/cool" component={Something}/>
注意: <Route component> 的优先级要比 <Route render> 高,所以不要在同一个 <Route> 中同时使用这两个属性。
<Link>
- to(string/object):要跳转的路径或地址;
- replace(bool):为 true 时,点击链接后将使用新地址替换掉访问历史记录里面的原地址;为 false 时,点击链接后将在原有访问历史记录的基础上添加一个新的纪录。默认为 false;
// to 为 string
<Link to="/about"> 关于 </Link>
// to 为 obj
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: {fromDashboard: true}
}}/>
// replace
<Link to="/courses" replace />
<NavLink>
<NavLink> 是 <Link> 的一个特定版本, 会在匹配上当前 URL 的时候会给已经渲染的元素添加样式参数,组件属性:
- activeClassName(string):设置选中样式,默认值为 active;
- activeStyle(object):当元素被选中时, 为此元素添加样式;
- exact(bool):为 true 时, 只有当地址完全匹配 class 和 style 才会应用;
- strict(bool):为 true 时,在确定位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线;
- isActive(func):判断链接是否激活的额外逻辑的功能;
// activeClassName 选中时样式为 selected
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
// 选中时样式为 activeStyle 的样式设置
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
// 当 event id 为奇数的时候,激活链接
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>
<Switch>
该组件用来渲染匹配地址的第一个 <Route> 或者 <Redirect>。那么它与使用一堆 route 又有什么区别呢?
<Switch> 的独特之处是独它仅仅渲染一个路由。相反地,每一个包含匹配地址 (location) 的 <Route> 都会被渲染。思考下面的代码:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
如果现在的 URL 是 /about,那么 <About>, <User>, 还有 <NoMatch> 都会被渲染,因为它们都与路径 (path) 匹配。这种设计,允许我们以多种方式将多个 <Route> 组合到我们的应用程序中,例如侧栏(sidebars),面包屑(breadcrumbs),bootstrap tabs 等等。然而,偶尔我们只想选择一个 <Route> 来渲染。如果我们现在处于 /about,我们也不希望匹配 /:user(或者显示我们的“404”页面)。以下是使用 Switch 的方法来实现:
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Switch>
现在,如果我们处于 /about,<Switch> 将开始寻找匹配的 <Route>。<Route path=”/about”/> 将被匹配,<Switch> 将停止寻找匹配并渲染 <About>。同样,如果我们处于 /michael,<User> 将被渲染。