react-router温故知新

谁等待了足够的时间,谁就将永远等待下去,超过了某一个期限,就什么也不会发生了。 —— 塞缪尔·贝克特 《马龙之死》

基本用法

Router组件本身只是一个容器,真正的路由要通过Route组件定义。Route组件定义了URL路径与组件的对应关系。

嵌套

注释:导航栏 应该在每一个屏幕中都有,如果没有react router,我们将把ul封装为一个组件,比如Nav,然后将 Nav 渲染近每一个屏幕;
但是随着项目的复杂度的增加,会使得项目代码冗余,react-router提供了另外一种方式和嵌套路由共享UI

React Router embraces this by letting you nest your routes, which automatically becomes nested UI.通过让你嵌套路由,自然形成嵌套的UI
The best way to build large things is to stitch small things together.
这才是react-router的真正威力,每一条route都可以作为一个独立的应用程序来开发

 04 嵌套

Link 不同于 a 标签的一个原因是,Link 可以区别这个链接是否是被激活的(active),以便于开发者标记不同的样式。行内样式 或者 className都是支持的,并且parent routes are active when child routes are active

1
2
3
4
5
6
7
// modules/App.js
<li><Link to="/about" activeStyle={{ color: 'red' }}>About</Link></li>
<li><Link to="/repos" activeStyle={{ color: 'red' }}>Repos</Link></li>

// modules/App.js
<li><Link to="/about" activeClassName="active">About</Link></li>
<li><Link to="/repos" activeClassName="active">Repos</Link></li>

active styles

如果将每一个有激活样式的Link都写上样式,会产生很多冗余代码,所以我们可以把有激活样式的Link封装一下,在需要使用的时候 引用 封装后的NavLink

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// moudle/NavLink.js
import React from 'react';
import {Link} from 'react-router';
export default class NavLink extends React.Component{
render(){
return <Link {...this.props} activeStyle = {{color:'red'}}></Link>
}
}


// moudle/App.js

<li><NavLink to="/about" >About</NavLink></li>
<li><NavLink to="/repos" >Repos</NavLink></li>

URL Params

1
/repos/reactjs/react-rpute

These URLs would match a route path like this:

1
/repos/:userName/:repoName

URL中用 : 开头的参数的值,可以在组件中用 this.props.params[name]取到

1
2
3
4
5
6
// repo.js
render(){
return(
<div >{this.props.params.repoName}</div>
)
}

1
2
3
4
// index.js
<Route path="/">
<Route path="/repo/:about/:URLparams" component={Repo}></Route>
</Route>

引用repo

1
2
// about.js
<Link to="/repo/About/URLParams">点击链接repo.js</Link>

Index Routes

当我们访问’/‘时,发现这只是一个导航并且显示一张空包的页面,所以我们可以设置一个默认页面,当App中没有子组件的时候,渲染Home

1
2
3
4
5
6
7
8
// Home.js
import React from 'react'

export default React.createClass({
render() {
return <div>Home</div>
}
})

1
2
3
4
5
6
7
8
9
// modules/App.js
import Home from './Home'

// ...
<div>
{/* ... */}
{this.props.children || <Home/>}
</div>
//...

虽然这样也可以运行的很好,但是我们想做的是小apps内构件小app,而不是大的应用程序,所以我们要把Home链接到Route中,像APP和About一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// index.js
// new imports:
// add `IndexRoute` to 'react-router' imports
import { Router, Route, hashHistory, IndexRoute } from 'react-router'
// and the Home component
import Home from './modules/Home'

// ...

render((
<Router history={hashHistory}>
<Route path="/" component={App}>

{/* add it here, as a child of `/` */}
<IndexRoute component={Home}/>

<Route path="/repos" component={Repos}>
<Route path="/repos/:userName/:repoName" component={Repo}/>
</Route>
<Route path="/about" component={About}/>
</Route>
</Router>
), document.getElementById('app'))

“如果子组件是active状态的,那么父组件一定也是active状态”,‘/’是所有路由的父导航,所以Home一直都是active状态
Home会一直active状态
有两种方法可以让router知道点击的是‘index route’,然后只渲染index route

1
2
3
4
5
// App.js
import { IndexLink } from 'react-router'

// ...
<li><IndexLink to="/" activeClassName="active">Home</IndexLink></li>

onlyActiveOnIndex

1
<li><Link to="/" activeClassName="active" onlyActiveOnIndex={true}>Home</Link></li>

这样我们要一直记得 activeClassName的类名,因为我们已经抽象出NavLink,而且 记住 我们已经把NavLink 的所有方法,通过{…props}都传递给了Link。
所以,我们可以简化

1
<li><NavLink to="/" onlyActiveOnIndex={true}>Home</NavLink></li>

Home只在选中时才激活

Clean Urls

Modern browsers let JavaScript manipulate the URL without making an http request, so we don’t need to rely on the hash (#) portion of the url to do routing, but there’s a catch (we’ll get to it later).
译:现代浏览器允许js在不触发http请求的时候操作url,所以我们不需要依赖url的哈希部分来进行路由

Configuring Your Server

当切换hashHistory成BrowserHistory之后,发现url中那些 hash 都不见了,url变得很干净,但是有一个问题当刷新页面的时候,就找不到页面了
因为无论什么url进来,你的服务器都需要传送给你的应用程序,但是因为应用程序操作了url。所以我们当前的浏览器不知道如何处理这个url。

  • 步骤一:–history-api-fallback
    Webpack Dev Server 有一个选项可以解决这个问题

    1
    2
    3
    // package.json

    "start": "webpack-dev-server --inline --content-base . --history-api-fallback"
  • 步骤二:在index.html中,把相对路径 改为 绝对路径

1
2
3
4
5
6
<!-- index.html -->
<!-- index.css -> /index.css -->
<link rel="stylesheet" href="/index.css">

<!-- bundle.js -> /bundle.js -->
<script src="/bundle.js"></script>

如果服务器在运行中,请关掉重新npm start一下,因为改动了index.html不会热加载。