zoukankan      html  css  js  c++  java
  • 学习React Router

    概念

    “路由”是一个随处可见的东西,比如一座城里会有若干条道路通往若干个目的地,一个司机可以选择从哪条路到哪个地方。在单页面应用中会有若干个按钮或链接指向若干个组件或页面,有个叫路由器的东西就是用来设置路径和组件的对应关系的。

    路由这个概念包含了三个部分:路径、目的地、路由器

    React Router

    React项目的路由库是 React Router,它分为三个部分:

    • react-router:核心组件
    • react-router-dom:浏览器路由库
    • react-router-native:native端路由库

    核心库会随着两个端的库安装,所以在浏览器端只需要安装react-router-dom

    组件

    根据路由的概念,React Router也提供了三大类组件:

    • Link:让一个元素指向某个路径,比如:<Link to="/home"首页</Link

    • Route:指定路径和组件的对应关系,比如:<Route path="/home" component={Home} /

    • Router:当链接被点击时,在若干个Route中寻找路径匹配的那一个,并渲染指定的组件

    每类组件都针对不同的客户端提供了不同的组件,比如Router组件在浏览器端(其他端先不管)就提供了两种组件:<BrowserRouter><HashRouter>

    BrowserRouter 和 HashRouter

    这两种组件分别是基于URL的pathname段和hash段的,很大的一个差别就是使用BrowserRouter时需要对服务器做一些设置,因为pathname会被发送到服务端。

    一个简单应用

    上图中黑框代表整个应用<App />,由<Header /><Menu /><Content />组成。<Menu />中设置了三个菜单项,点击后分别将对应的组件渲染到<Content中 />,而<Header />则可以用来显示面包屑等组件。当前选中第三条菜单,渲染了<App3 /> 组件。这个组件内部又有两个链接,分别指向不同的组件。

    在这个应用中,路由发生了嵌套:

    • App

      • /app1
      • /app2
      • /app3
        • /app3-1
        • /app3-2

    路由配置

    现在可以简单配置一下路由了,可以看到,不必把所有路由都放到一处。以下代码的,而各个组件的具体内容则简单放个标题也可以。

    需要注意:

    • 必须用Router组件包裹整个应用,可以用HashRouter或者BrowserRouter
    • 可以在子组件内继续添加路由,但要记得把父组件所在的路由传递进去
    //App.js
    import React from "react";
    import { HashRouter as Router, Route, Link, NavLink } from "react-router-dom";
    import App1 from './App1'
    import App2 from './App2'
    import App3 from './App3'
    import Header from './Header'
    import Menu from './Menu'
    import Content from './Content'
    
    export default class MyApp extends React.Component{
    render(){
       return(
           <Router basename="/myapp"
             <div
               <Header /
               /* Menu组件下传了三个Link */
               /* 像这样传进来的组件,在Menu内部通过props.children就可以访问 */ 
               <Menu
                 <Link to="/app1"App1</Link        
                 <Link to="/app2"App3</Link
                 <Link to="/app3"App3</Link
               </Menu
             </div
    
             <Content
               <Route path="/app1" component={App1} /    
               <Route path="/app2" component={App2} /
               <Route path="/app3" render={()=(<App3 basePath="/app3" /)} /
             </Content
           </Router
         )
      }
    }
    
    /*
     * App3内部又有路由配置
     * 需要注意的是,主路由在App组件里,所以得把进入App3组件时已有的路由(取名basePath)传进来
    */
    import { Route, Link } from "react-router-dom";
    import Nav from './Nav'
    import App3_1 from './App3-1'
    import App3_2 from './App3-2'
    
    export default const App3 = () = (
      <div
         <Nav
             <Link to={this.props.basePath + "/app3-1"}App3-1</Link
             <Link to={this.props.basePath + "/app3-2"}App3-2</Link
         </Nav
         <Route path={this.props.basePath + "/app3-1"} component={App3_1} /
         <Route path={this.props.basePath + "/app3-2"} component={App3_2} /
      </div
    )
    

    有了这个应用骨架,剩下的问题就好办了,接下来还需要考虑这几个问题:

    1. 路由匹配

    当一个<Link被点击时,其to属性的值就被拿去和Route的path属性匹配。

    路由其实就是目录层级结构的表示,Route就相当于对文件系统的描述,一个Route就表示了哪个路径下有哪个组件。

    路由匹配就是拿Link的to属性值去看看它能够被哪个目录所包含,比如:有三个Route,分别是//abc/abc/123,显然从前到后是包含关系。此时如果有一个路径为/abc/123/xyz的Link被点击,那么这三个Route都会匹配到。

    那么问题来了,由于匹配到的Route都会被渲染,上面的结果就是点一个链接渲染了三个组件,而我们期望的是只渲染/abc/123/xyz,我只知道两个解决方法:

     /*-------------------- 方法1 -------------------*/
     /* exact:让上级Route只匹配路径完全一样的Link */
     <Route exact path="/" component={App1} /	//只匹配“/”,不匹配“/...”
     <Route exact path="/abc" component={App2} /	//只匹配“/abc”,不匹配“/abc/...”
     <Route path="/abc/123/xyz" component={App3} /
     
     /*-------------------- 方法2 -------------------*/
     /* switch:只渲染第一个匹配到的,此时要注意把上级目录的Route往下面放 */
     <Switch
       /* 虽然三个都匹配了,但Switch使得只有第一个被渲染 */
         <Route path="/abc/123/xyz" component={App3} /	
         <Route path="/abc" component={App2} /	
         <Route path="/" component={App1} /		
       </Switch
    

    NavLink是特殊的Link,匹配到后,可以给它添加activeStyle或者activeClassName。

    需要注意的是,匹配是Link和Route双方的事情,NavLink能够“感知”匹配从而改变自身样式,所以也要解决多个NavLink同时感知到匹配的问题,所以NavLink也需要使用exact,不然的话点击下级目录链接会导致所有上级目录Link变样式:

     <NavLink exact to="/" activeStyle={{color: 'red'}}App1</NavLink
     <NavLink exact to="/abc" activeStyle={{color: 'red'}}App1</NavLink
     <NavLink exact to="/abc/123/xyz" activeStyle={{color: 'red'}}App1</NavLink
    

    3. Route的三种渲染方式

    • component:给什么渲染什么

    • render:可以在渲染之前做点别的

       <Route path="/" render={()={
       	console.log("额外的逻辑")
          return <AppX /
        }/
    
    • children:可以根据是否匹配渲染不同组件,是否匹配可由自动传入的参数props.match获知
       <Route path="/" children={(props)={
       	console.log("额外的逻辑")
        	return props.match ? <AppX : <AppY
        }/
    

    无论是否匹配到,children函数都会执行。不要在Switch中使用children!

    4. 更多信息

    一个路由被匹配到,其对应组件就会被传入三个props:match、location、history

    URL参数

    Link中可以给路由传参:

     <Route path="/app/:id" component={App1} /
     <Link to="/app/:123456"To App1</Link
    

    这个参数可以通过match.params.id拿到。

  • 相关阅读:
    Core Animation 文档翻译—附录C(KVC扩展)
    Core Animation 文档翻译—附录B(可动画的属性)
    Core Animation 文档翻译—附录A(Layer样貌相关属性动画)
    Core Animation 文档翻译 (第八篇)—提高动画的性能
    Core Animation 文档翻译 (第七篇)—改变Layer的默认动画
    Core Animation 文档翻译 (第六篇)—高级动画技巧
    Core Animation 文档翻译 (第五篇)—构建Layer的层次结构
    用Markdown快速排版一片文章
    Core Animation 文档翻译 (第四篇)—让Layer的content动画起来
    Core Animation 文档翻译(第三篇)—设置Layer对象
  • 原文地址:https://www.cnblogs.com/MPK-dev/p/12900376.html
Copyright © 2011-2022 走看看