React-Router学习整理

欢迎大家指导与讨论 : )

  一、前言

    本文摘要:react-router的基本用法动画效果与路由,路由权限控制,路由离开确认,根据路由切分的按需加载,路由组件的属性。本文是笔者在学习时整理的笔记,由于技术水平还不够高,有错误的地方恳请各位指出,共同进步O(∩_∩)O

  二、基本用法

    二、1 路由定义(摘要: Router, Route)

      在一个路由系统中,我们需要定义好路由表。我们需要用Router组件包含我们的路由表,通过Route来声明单个的路由。同时,每个路由应该与它所属的组件一一对应

render((
  <Router >//开始创建路由表
    <Route path="/" component={App}>//声明每一个路由
      <Route path="/about" component={About}/>
      <Route path="users" component={Users}>//每个路由
        <Route path=":id" component={User}/>//对应一个Component
      </Route>
    </Route>
  </Router>
), document.getElementById('example'))

//其他定义路由表的方法

import routes from './config/routes'

render(<Router history={browserHistory} routes={routes}/>, document.getElementById('example'))

    二、2 路由嵌套(摘要: IndexRouter, this.props.children)

      如何实现路由的嵌套呢,与Angular路由一样,路由的嵌套需要两个条件。一、在创建路由表的时候就声明好嵌套的规则(ng中的$stateProvider);二、需要有一个view来安放所要嵌套的子页面(ng中的ui-view)。其中,我们还可以在嵌套层的首个路由声明中,使用IndexRoute来声明该路由下的默认路由(类似于ng中$urlProvider.otherwise)

//有嵌套与默认页面的路由表
render((
  <Router >
    <Route path="/" component={App}>
      <IndexRoute component={Index}/>//设置默认页面
      <Route path="/about" component={About}/>
      <Route path="users" component={Users}>
        <IndexRoute component={UsersIndex}/>//设置默认页面
        <Route path=":id" component={User}/>
      </Route>
    </Route>
  </Router>
), document.getElementById('example'))

//一个用于安放子页(子路由)的view
class Users extends React.Component {
  render() {
    return (
      <div>
        <h2>Users</h2>
        {this.props.children}//此处相当于<ui-view>
      </div>
    )
  }
}

    二、3 路由跳转(摘要: Link,to)

      我们需要一个Link组件帮助我们实现路由的的跳转  <li><Link to="/users" >/users</Link></li> ,最终Link组件会被渲染为<a>标签。to属性是我们所要跳转的路由pathname(类似于ng中的ui-sref / href)

      二、3 . 1 父子路由的参数穿透传递(摘要: to = {`/xx/${xxx}/`} )

        若父路由中包含不确定参数,而我们又想把该参数往下级传递,这时候我们需要这样子做

//路由配置
      <Route path="user/:userID" component={User}>
        <Route path="tasks/:taskID" component={Task} />
        <Redirect from="todos/:taskID" to="tasks/:taskID" />
      </Route>
//子级路由
<li><Link to={`/user/${userID}/tasks/foo`} activeClassName="active">foo task</Link></li>

      二、3 . 2 带参数的路由跳转

<li><Link      to={{ pathname: '/users/ryan', query: { foo: 'bar' } }} activeStyle={ACTIVE}>/users/ryan?foo=bar</Link></li>

      二、3 . 3 函数内跳转(摘要: this.context.router.push('/'))

          this.context.router.push('/') ,注:这个写法会把跳转载入浏览器历史,若不想留下历史记录则可以 this.context.router.replace('/') 

  三、带有动画效果的路由切换(摘要: ReactCSSTransitionGroup)

    当我们需要在路由切换时带有一定的动画效果时,我们便需要 react-addons-css-transition-group 这个插件了。使用ReactCSSTransitionGroup组件来包含我们需要呈现动画效果的view

class App extends Component {
  render() {
    return (
      <div>
        <ul>
          <li><Link to="/page1">Page 1</Link></li>
          <li><Link to="/page2">Page 2</Link></li>
        </ul>

        <ReactCSSTransitionGroup component="div"  transitionName="example"  transitionEnterTimeout={500}  transitionLeaveTimeout={500}
        >
          {React.cloneElement(this.props.children, {
            key: this.props.location.pathname
          })}
        </ReactCSSTransitionGroup>
           //克隆所有子节点,单独的{this.props.children}没有动画效果
      </div>
    )
  }
}

  四、路由的权限控制(摘要: onEnter、context.router)

    单页应用路由的权限控制的基本思路是:监听路由的改变,每当路由将要发生改变,我们就使用一个中间服务(该服务介于上一级路由和将要到达路由之间启动),来判断我们是否有进入这个路由的权限,有的话直接进入,没有的话就redirect。在React中,为某个路由进行权限监听的方式是onEnter <Route path="page" component={Page} onEnter={requireCredentials}/> ,该onEnter属性对应连着一个具有判断权限的中间服务。我们通过上一级路由来启动这个服务。假设我们需要从'/form'到'/page'之间做一个判断,在'/form'中填写特定字段后才能成功跳转,否则redirect到'/error'

//form
const Form = createClass({
  //省略部分代码
  submitAction(event) {
    event.preventDefault();
     //通过context传输数据
    //通过url的query字段传输数据
    //也可以通过制定其他服务来传输数据
    this.context.router.push({
      pathname: '/page',
      query: {
        qsparam: this.state.value
      }
    })
  },
  render() {
    return (
      <form onSubmit={this.submitAction}>
        //省略部分代码
        <button type="submit">Submit </button>
      </form>
    )
  }
})

//路由权限控制
<Route path="page" component={Page} onEnter={requireCredentials}/>

//权限控制的中间服务
function requireCredentials(nextState, replace, next) {
  //获取传输过来的数据
  if (query.qsparam) {
    serverAuth(query.qsparam)
    .then(
      () => next(),//成功,通过next()成功跳转
      () => {
        replace('/error')//重定向
        next()
      }
    )
  } else {
    replace('/error')
    next()
  }
}  

     其中,onEnter所指向的函数是 type EnterHook = (nextState: RouterState, replace: RedirectFunction, callback?: Function) => any; 其中,nextState作为第一个参数,其所带的信息有如下:

type RouterState = {
  location: Location;
  routes: Array<Route>;
  params: Params;
  components: Array<Component>;
};

       其中,replace函数一旦被使用到,则在函数内部跳转到一个新url,返回时也要带上必要的信息,如下

type RedirectFunction = (state: ?LocationState, pathname: Pathname | Path, query: ?Query) => void;

   六、路由离开确认(摘要: componentWillMount, this.context.router.setRouteLeaveHook) 

     若我们需要在路由切换,在离开当前页面的时候做一些确认工作,我们可以通过setRouteLeaveHook函数,为离开前执行一些操作

//Component内部
  componentWillMount() {
    this.context.router.setRouteLeaveHook(
      this.props.route,
      this.routerWillLeave
    )
  }
  
  routerWillLeave() {
    if (xxx)
     //...
  },

  七、根据路由按需加载组件

    按需加载在单页应用中的好处不言而喻,按业务模块切分代码能使首次加载资源所需要的时间大大降低,能在一定程度上增强用户体验。但首先我们需要整理一下我们的项目结构(此demo是按路由切分的,另外还能按业务模块进行切分)

    七 . 1 项目结构

    七 . 2 路由表配置(app.js)

    七 . 3 对应组件的加载配置(routes/hello/index.js和routes/test/index.js)

  八、路由组件的属性(摘要: this.props)

  九、路由Location属性

type Location = {
  pathname: Pathname;
  search: QueryString;
  query: Query;
  state: LocationState;
  action: Action;
  key: LocationKey;
};
原文地址:https://www.cnblogs.com/BestMePeng/p/React_Router.html