zoukankan      html  css  js  c++  java
  • react-router 学习笔记

    前言:

      本文为个人学习react-router的总结。包括路由基础配置,跳转,权限管理,组件与路由配置的关系,代码分割。欢迎交流指导。

    一、路由基础

      1.路由配置 & 显示路由组件的view(类比angular的ui-view)

      路由配置:路由匹配的规则

    复制代码
    render((
        <Router history={ hashHistory }>
            <Route path="/" component={ App }>
                <Route path="select" component={ Select }></Route>
                <Route path="found" component={ Found }></Route>
                <Route path="follow" component={ Follow }></Route>
                <Route path="my" component={ My }>
                    <Route path=":myname" component={ MyName }></Route>
                    <Route path="mysex" component={ MySex }></Route>
                </Route>
            </Route>
        </Router>
    ), document.getElementById('root'));
    复制代码

      view:放置路由组件的地方(URL匹配了,然后对应的组件应该放到什么地方去),

      每一个Route都只是一个组件,子路由就是 this.props.children 里面的组件,Route通过匹配URL决定显示哪一个子路由

    复制代码
    class App extends PureComponent {
        render() {
            return (
                <div>
                    <GlobalNav />
                    { this.props.children } { /* this.props.children 是被嵌套在App的组件,相当于放子路由的View*/}
                </div>
            )
        }
    }
    复制代码

    二、默认路由(IndexRoute )

      组件<App /> 的匹配路径是 ‘/', 有四个子路由,当前路由只是'/',那么<App />应该显示什么页面呢?

      这里给与IndexRoute组件 -- 若希望直接使用4个其中一个则使用IndexRedirect

    复制代码
    render((
        <Router history={ hashHistory }>
            <Route path="/" component={ App }>
                <IndexRoute component={ IndexApp } />
                <Route path="select" component={ Select }></Route>
                <Route path="found" component={ Found }></Route>
                <Route path="follow" component={ Follow }></Route>
                <Route path="my" component={ My }>
                    <Route path=":myname" component={ MyName }></Route>
                    <Route path="mysex" component={ MySex }></Route>
                </Route>
            </Route>
        </Router>
    ), document.getElementById('root'));
    复制代码

       如果不使用IndexRoute组件,也还有一种投机取巧的方法,直接在 App组件中,使用  {this.props.children || <IndexApp />} ,在ui展示的层面上修改this.props.children为undefined的情况。

       缺点:这种形式,没有参与到路由机制中,onEnter,onLeave 等HOOK都无法使用

    三、路由跳转   

      1. IndexLink & Link (active状态之争)

       倘若有如下两个链接,正好URL是'/my/mioawwwww', 两个路由都匹配的了,那么就是两个都是active状态(相应地添加activeStyle,activeClassName的样式)

    <Link to="/my" >Mypage</Link>
    <Link to="/my/:myname" >myname</Link>

      若你只想为 <Link to="/my/:myname" >myname</Link> 这一个按钮添加active样式,就可以为 <Link to="/my">Mypage</Link> 使用IndexLink

    <IndexLink to="/my" >Mypage</IndexLink>
    <Link to="/my/:myname" >myname</Link>

      IndexLink是补充Link的,只要URL完整匹配'/my'的时候才会激活active状态

      2.跳转参数 to

         2.1:通过 to=’xx/xx' 直接跳转 <Link to={`/my/${myname}/info`}>check my info</Link> 

         2.2:to=对象,带参数跳转(pathname, query, hash, state(额外数据)),注意:这些参数都被存放到this.props.location中

     <li><Link to={{pathname:"/select", hash:'#ahash', query:{foo: 'bar', boo:'boz'}, state:{data:'miao'}  }} activeClassName="GlobalNav-active">精选</Link></li>

         2.3:to=函数,注册到路由跳转事件中,每一次路由变化,都会执行该函数,并经最新的location作为参数

    <Link to={location => ({ ...location, query: { name: 'ryan' } })}>
      Hello
    </Link>

        2.4:不使用Link,在函数内直接操作router

          旧版本:由于router只用的context传递路由信息,因此每一个组件都可以轻易的通过this.context.router获取路由

          新版本:router被放置在this.props中,通过this.props.router可以获取路由

          注意:push与replace的区别,一个是添加,一个是替换,历史记录中被替换的已经不存在了,所以浏览器回退不到替换前的页面。

    复制代码
        changeRouter = () => {
            console.log(this.props)
            // this.props.router.push('/follow');
            // this.props.router.push({
            //     pathname:'/follow',
            //     state:{name:'xxx'},
            //     query: {foo: 'bar'}
            // })
            
            // this.props.router.replace('/follow');
            this.props.router.replace({
                pathname: '/follow',
                query: {foo:'bar'}
            })
        }
    复制代码

       3.若不是Route组件,而是Route的子组件,则this.props.router === undefined

        若不使用Link,有两种方法

        3.1 contextTypes

    复制代码
        static contextTypes = {
            router: PropTypes.object
        }
        handleClick = (e) => {
            e.stopPropagation();
            e.preventDefault();
            this.context.router.push('login');
                    //...
    复制代码

        3.2 引入browserHistory,hashHistory

    复制代码
    import {browserHistory} from 'react-router';
    //...
        handleClick = (e) => {
            e.stopPropagation();
            e.preventDefault();
            browserHistory.push('login')
            //...
    复制代码

    四、重定向

      <Redirect>:重定向到同等级的其他路由

       <Redirect from="name/xxx" to='mysex' /> 

    复制代码
    render((
        <Router history={ browserHistory }>
            <Route path="/" component={ App }>
                <IndexRoute component={ IndexApp } />
                <Route path="select" component={ Select }></Route>
                <Route path="found" component={ Found } onEnter={onEnterHook} onLeave={onLeaveHook}></Route>
                <Route path="follow" component={ Follow }>
                </Route>
                <Route path="my" component={ My } >
                    <Redirect from="name/xxx" to='mysex' />
                    
                    <Route path="name/:myname" component={ MyName }>
                        <Route path="info" component={ MyInfo } ></Route>
                    </Route>
                    <Route path="mysex" component={ MySex } />
                </Route>
                <Redirect from="*" to='/' />
            </Route>
        </Router>
    ), document.getElementById('root'));
    复制代码

      <IndexRedirect>:从父路由的目录开始重定向

    <Route path="/" component={App}>
      <IndexRedirect to="/welcome" />
      <Route path="welcome" component={Welcome} />
      <Route path="about" component={About} />
    </Route>

    五、路由机制的权限

      1.onEnter

    const onEnterHook = (nextState, replace /*,cb*//*若添加cb参数,钩子变成异步执行,cb返回之前,将发生阻塞*/) => {
        console.log('onenter', nextState);
        // replace // 是router.replace(),若访问者没有权限,则引导到其他页面
    }

      nextState的属性

      2.onLeave:与onEnter类似,nextState属性不同

       3.onChange(prevState, nextState, replace, callback?) ,用于子路由,

        进入该路由的某个子路由是触发,或者改变query,hash

        一旦添加onChange属性,则子路由通过onChangeHook决定,Link不起作用

       

     六、组件与路由的一一对应关系,按需加载组件

    <Route path="follow" component={ Follow }></Route> // this.props.children;
    <Route path="follow" component={ {main:Follow, sidebar: Sidebar} }></Route> // const { main, sidebar } = this.props;

       异步加载组件,使用(需要加上 require.ensure([], (require) => {}) 实现代码分割

       getComponent(nextState, callback)  &&  getComponents(nextState, callback) 

       cb(err, component) 

      getComponent(nextState, cb) {
        require.ensure([], (require) => {
          cb(null, require('./components/Calendar'))
        })
      }

       

     七、每一个Route组件的属性

     

     八、另一种路由配置的方式

    复制代码
    const selectRouter = {
        path:'select',
        component: Select
    }
    const foundRouter = {
        path:'found',
        component: Found
    }
    const myRouter = {
        path:'my',
        getComponent(nextState,cb) {
            cb(null, My)
        }
    }
    // import Follow from './components/Follow.js';
    const followRouter = {
        path:'follow',
        getComponent(nextState,cb) {
            require.ensure([], (require) => {
                cb(null, require('./components/Follow'))
            })
        }
        // getComponent(nextState, cb) {
        //     cb(null, Follow)
        // }
    }
    const rootRouter = {
        path: '/',
        component: App,
        // indexRoute: {component:IndexApp},
        childRoutes: [
            selectRouter,
            foundRouter,
            followRouter,
            // require('./components/Follow.index'),
            myRouter
            ]
    }
    // const rootRouter = {
    //     path: '/',
    //     component: App,
    //     getIndexRoute(partialNextState, cb) {
    //         cb(null,  {compoment:IndexApp});
    //     },
    //     getChildRoutes(location, cb) {
    //         cb(null, [
    //             selectRouter,
    //             foundRouter,
    //             followRouter,
    //             myRouter
    //         ])
    //     }
    // }
    render(
        <Router history={browserHistory} routes={rootRouter} />,
        document.getElementById('root')
    )
    复制代码

       代码分割的注意事项:

        1. require.ensure中分割的组件,需要使用module.export 暴露出来

    module.exports = xxx; //可获取xxx组件
    export default xxx // 不可获取xxx组件 

         2. getComponent,getComponents,getIndexRoute,getChildRoutes只是实现了异步加载,要实现代码分割还是要使用require.ensure

  • 相关阅读:
    小波变换的引入,通俗易懂
    Leetcode 437. Path Sum III
    Leetcode 113. Path Sum II
    Leetcode 112 Path Sum
    Leetcode 520 Detect Capital
    Leetcode 443 String Compression
    Leetcode 38 Count and Say
    python中的生成器(generator)总结
    python的random模块及加权随机算法的python实现
    leetcode 24. Swap Nodes in Pairs(链表)
  • 原文地址:https://www.cnblogs.com/chenliyang/p/6547825.html
Copyright © 2011-2022 走看看