React Router
路由可以向应用中快速的添加视图和数据流,同时保持页面与URL同步
import {Router ,Route, Link} from 'react-router'
class App extends React.Component {
        render(){
             return (
                <div>
                    <ul >
                        <li><Link to='/about'>About</Link></li>
                        <li><Link to='/inbox'>Inbox</Link></li>
                    </ul>
                    {this.props.children}
                </div>
                )}})
//获取URL参数
class Message extends React.Component{
    componentDidMount(){
      const id = this.props.params.id     //来自于路径 ‘/inbox/messages/:id'
      
      fetchMessage(id,function(err,message){
        this.setState({message:message})
      })
  }
  render(){
    return(
      <div>
          <h3>message{this.props.params.id}</h3>
      </div>
}
React.render((
            <Router>
                <Route path='/' component={App}>
                        <Route path='about' component={About} />
                        <Route path='inbox' component={Inbox} onEnter={requireAuth}>
                  <Route path='messages/:id component={Message} />
              </Route>
                </Route>
            <Router>
    ).document.body);
以上获取URL参数方法:
1 id = this.props.params.id 来自父组件路径path=‘/index/message.:id'
2 baz= this.props.location.query.bar 访问路径为 /foo?bar=baz 时,获取baz的值
3 newhash = window.location.hash 简单的用于跳转,不用存储location state
添加首页:IndexRouter 设置默认页面,当App的render中this.props.children还是undefined时显示
<IndexRoute component={Dashboard}/>
IndexLink
如果使用<Link to='/'>Home</Link>,他会一直处于激活状态,因为所有的URL开头都是‘/'。而我们希望仅仅在home被渲染之后才激活并链接它。 可以使用<IndexLink to='/'>home</IndexLink>.
简洁的URL:使用绝对路径,无需在URL中添加更多的层级,从而可以使用更简洁
<Route path='/messages/:id' component={Message}/> 但其可能在动态路由中无法使用
重定向Redirect
<Redirect from='message/:id' to='/message/:id'/>
当有人点击/inbox/message/5时,会跳到/message/5,以防/inbox/message/5不存在
onEnter和onLeave进入和离开的hook,在页面跳转确认时触发。例如 权限验证,或数据持久保存
onLeave hook 在所有将离开的路由中触发,从最下层的字路由开始到最外层的父路由结束。
onEnter hook从最外层的父路由开始到最下层的字路由结束
例如:从/messages/5跳到/about,hook的执行顺序:/messages/:id的onLeave->/inbox的onLeave->/about的onEnter
requireAuth(nextState,replace,callback){if(isLogined){replace('./home');}else{replace('./login');}callback();}
路径语法
:paramName 匹配位于/ ? # 之后的URL;称作参数
() 在其内部的内容是可选的
* 匹配任意字符
History
一个history知道如何去监听浏览器地址栏的变化,并解析这个url转化为location对象,然后router使用它匹配到路由,渲染对应的组件。
1 browserHistory
使用浏览器中的 historyAPI 用于处理URL,创建 example.com/some/path这样的真实URL
2 hashHistory
我使用URL中的hash#部分去创建形如 example.com/#/some/path的路由.window.location.hash = newhash
3 creactMemoryHistory
d Memory history 不会在地址栏被操作或读取,非常适合测试和其他渲染环境。但必须创建
const history = createMemoryHistory(location)
高级进阶
动态路由:
根据‘按需加载’的原则,路由非常适合做代码拆分:他的责任就是配置好每个view。
react router 的 路径匹配 及 组件加载 都是异步完成的,不仅允许你延迟加载组件,也可以延迟加载 路由的配置。在首次加载包中只需要有一个路径定义,路由会自动解析剩下的路径。
route定义的函数 getChildRoutes、getIndexRoute、getComponents 都为异步加载‘逐渐匹配’
const CourseRoute = { path:'cource/:id', getChildRoutes(location,callback){ require.ensure([],function(require){ callback(null,[ require('./routes/Announcements'), require('./routes/Assignments'), require('./routes/Grades'), ])})}, getIndexRoute(location,callback){ require.ensure([],function(require){ callback(null,require('./components/Index')) })}} getComponents(location,callback){ require.ensure([],function(require){ callback(null,require('./components/Course'))})}}
跳转前确认:React Route 提供一个routerWillLeave的生命周期钩子,使得react组件可以拦截正在发生的跳转,或在离开route前提示用户。
routerWillLeave 返回值有以下两种:
1 return false 取消此次跳转
2 return 返回提示信息,在离开route前提示用户进行确认。
使用:1在route组件中引入 lifecycle mixin来安装这个钩子
import { Lifecycle } from 'react-router'
const Home = React.creactClass({
    //假设Home是一个 route 组件,使用 Lifecycle mixin 去获取一个 routerWillLeave 方法。
    mixins:[Lifecycle],
    
    routerWillLeave(nextLocation){
        if(!this.state.isSaved)
            return 'Your work is not saved! Are you sure leave?'
    },
    .....
})
2 如果想在一个深层次嵌套的组件中使用 routerWillLeave 钩子,只需在route组件中引入RouteContext mixin,这样就会把route放到context中。
import { Lifecycle, RouteContext } from 'react-router'
const Home  = React.creactClass ({
        //route 会被放在Home 和它子组件及孙子组件的context中,这样在层级树中Home及其所有子组件都可以拿到 route。
        mixin: [ RouteContext ],
        render(){
            return <NestedForm />
        } })
const NestedForm = React.creactClass({
         //后代组件使用Lifecycle mixin 获得 一个routerWillLeave 的方法。
        mixins:[Lifecycle],
        routerWillLeave(nextLocation){
            if(!this.state.isSave)
            return 'your work is not saved !'
        },
        ......
})
服务端渲染:
需求:放生错误时返回500, 需要重定向时返回30x,在渲染之前获得数据router
方法:在<Router>API下一层使用:
1 使用 match 在渲染之前根据 location 匹配route
2 使用 RoutingContext 同步渲染 route 组件
import { renderToString } from 'react-dom/server'
import { match,RoutingContext } from 'react-router'
import routes from './routes'
serve((req,res) => {
     //这里的req.url应该是从初识请求中获得的
    //完整的URL路径,包括查询字符串
    match({routes,location:req.url},{error,redirectLocation,renderProps) => {
    if(error){
        res.send(500,error.message)
        }else if (redirectLocation){
        res.redirect(302,redirectLocation.pathname + redirectLocation.search
        }else if (renderProps){
        res.send(200,renderToString(<RoutingContext {...renderProps}   //renderProps可以构建任何想要的形势
        }else{
        res.send(404,'Not found')
        }})})
路由组件的生命周期中获取数据:最简单的方法是通过router组件的生命周期Hook来实现。
理解当路由改变时组件生命周期的变化,可以在Invoice组件里实现一个简单的数据获取功能
let Invoice = React.creactClass({ getInitialState(){ return { invoice:null } }, componentDidMount(){ //初始化数据 this.fetchInvoice() }, componentDidUpdate(prevProps){ //通过参数更新数据 let oldId = prevProps.params.invoiceId let newId = this.props.params.invoiceId if (newId !== oldId) this.fetchInvoice() }, componentWillUnmount(){ //在组件移除前 忽略正在进行中的请求 this.ignoreLastFetch = true }, fetchInvoice(){ let url = '/api/invoices/${this.props.params.invoiceId} this.request = fetch(url,(err,data) => { if (!this.ignoreLastFetch) this.setState({invoice:data.invoice}) }) }, render(){ return <InvoiceView invoice = {this.state.invoice}/> } })
组件外部跳转:
在组件内部使用this.context.router来实现导航;
在组件外部使用Router组件上被赋予的history可以实现导航。
//main file 里renders a Router import { Router,browserHistory } from 'react-router' import routes from './app/routes' render(<Router history={browserHistory} routers={routes} />.el) // a redux/flux action file: import { browserHistory } from 'react-router' browserHistory.push('/some/path')
浏览器的前进后退按钮发生了什么????
web浏览器的历史记录相当于一个仅有入栈的栈,当用户浏览器到某一个页面时将该文档存入到栈中,点击「后退」或「前进」按钮时移动指针到 history 栈中对应的某一个文档。
- 使用 hashchange事件来监听window.location.hash的变化
- hash 发生变化浏览器会更新 URL,并且在 history 栈中产生一条记录
- 路由系统会将所有的路由信息都保存到 location.hash中
- 在 react-router 内部注册了 window.addEventListener('hashchange', listener, false)事件监听器
- listener 内部可以通过 hash fragment 获取到当前 URL 对应的 location 对象
在react中监听路由hash改变,包括 浏览器前进回退按钮 :componentWillReceiveProps(nextProps){if(nextProps.location.pathname != this.props.location.pathname){window.addEventListener('hashchange',listener,false)};
点击Link后 路由系统发生????
它的 to、query、hash 属性会被组合在一起并渲染为 href 属性。然后调用history.pushState(state,path) ,
然后调用 window.location.hash 或者 window.history.pushState() 修改了应用的 URL

 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号