• 学习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拿到。

  • 相关阅读:
    作用域链及作用域面试题
    this在js中的作用
    dom对象
    作用域问题
    逻辑运算
    socket.io 的使用
    mongoDB 的使用
    使用 usb 调试的时候,连接上电脑没反应
    uni-app 的更新及碰到的问题
    WebSocket 的使用
  • 原文地址:https://www.cnblogs.com/MPK-dev/p/12900376.html
Copyright © 2020-2023  润新知