乐趣区

关于前端:无废话快速上手React路由

本文以简洁为指标,帮忙疾速上手 react-router-dom 默认你接触过路由相干的开发

装置

输出以下命令进行装置:

// npm
npm install react-router-dom

// yarn
yarn add react-router-dom

react-router 相干标签

react-router罕用的组件有以下八个:

import { 
  BrowserRouter,
  HashRouter,
  Route,
  Redirect,
  Switch,
  Link,
  NavLink,
  withRouter,
} from 'react-router-dom'

简略路由跳转

实现一个简略的一级路由跳转

import { 
    BrowserRouter as Router, 
    Route, 
    Link 
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        <Link to="/home" className="link"> 跳转 Home 页面 </Link>
        <Link to="/about" className="link"> 跳转 About 页面 </Link>
        <Route path="/home" component={Home}/>
        <Route path="/about" component={About}/>
      </Router>
    </div>
  );
}

export default App;

成果如下:

要点总结:

  1. Route组件必须在 Router 组件外部
  2. Link组件的 to 属性的值为点击后跳转的门路
  3. Route组建的 path 属性是与 Link 标签的 to 属性匹配的; component属性示意 Route 组件匹配胜利后渲染的组件对象

嵌套路由跳转

React 的路由匹配层级是有程序的

例如,在 App 组件中,设置了两个路由组件的匹配门路,别离是 /home/about,代码如下:

import { 
  BrowserRouter as Router, 
  Route, 
  Link,
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {

  return (
    <div className="App">
      <Router>
        <Link to="/home"> 跳转 Home 页面 </Link>
        <Link to="/about"> 跳转 About 页面 </Link>

        <Route path="/home" component={Home}/>
        <Route path="/about" component={About}/>                           

      </Router>
    </div>
  );
}

export default App;

而后 Home 组件中同样也想设置两个路由组件的匹配门路,别离是 /home/one/home/two,此时就能够看出,这个 /home/one/home/two 为上一级路由 /home 的二级嵌套路由,代码如下:

import React from 'react'
import {
    Route,
    Link,
} from 'react-router-dom'
import One from './one'
import Two from './two'

function Home () {
    
    return (
        <>
            我是 Home 页面
            <Link to="/home/one"> 跳转到 Home/one 页面 </Link>
            <Link to="/home/two"> 跳转到 Home/two 页面 </Link>

            <Route path="/home/one" component={One}/>
            <Route path="/home/two" component={Two}/>
        </>
    )
}

export default Home

特地留神: Home 组件中的路由组件 One 的二级路由门路匹配必须要写 /home/one,而不是 /one,不要认为 One 组件看似在 Home 组件内就能够简写成 /one

动静链接

NavLink能够将以后处于 active 状态的链接附加一个 active 类名,例如:

import { 
    BrowserRouter as Router, 
    Route, 
    NavLink 
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        <NavLink to="/home" className="link"> 跳转 Home 页面 </NavLink>
        <NavLink to="/about" className="link"> 跳转 About 页面 </NavLink>
        <Route path="/home" component={Home}/>
        <Route path="/about" component={About}/>
      </Router>
    </div>
  );
}

export default App;
/* 设置 active 类的款式 */
.active {
    font-weight: blod;
    color: red;
}

成果如下:

路由匹配优化

当点击跳转链接时,会主动去尝试匹配所有的 Route 对应的门路,如图所示:

失常状况下,只需匹配到一个规定,渲染即可,即匹配胜利一个后,无需进行后续的匹配尝试,此时能够用 Switch 组件,如下所示:

import { 
  BrowserRouter as Router, 
  Route, 
  NavLink,
  Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        <NavLink to="/home" className="link"> 跳转 Home 页面 </NavLink>   
        <NavLink to="/about" className="link"> 跳转 About 页面 </NavLink>

        <Switch>
          <Route path="/home" component={Home}/>       
          <Route path="/about" component={About}/>      
          <Route path="/home" component={Home}/>       
          <Route path="/home" component={Home}/>        
          {/* 此处省略一万个 Route 组件 */}                  
          <Route path="/home" component={Home}/>                           
        </Switch>

      </Router>
    </div>
  );
}

export default App;

成果如下:

要点总结:

  1. 将多个 Route 组件同时放在一个 Switch 组件中,即可防止屡次无意义的路由匹配,以此晋升性能

重定向

当页面跳转时,若跳转链接没有匹配上任何一个 Route 组件,那么就会显示 404 页面,所以咱们须要一个重定向组件 Redirect,代码如下:

import { 
  BrowserRouter as Router, 
  Route, 
  NavLink,
  Switch,
  Redirect,
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        <NavLink to="/home" className="link"> 跳转 Home 页面 </NavLink>   
        <NavLink to="/about" className="link"> 跳转 About 页面 </NavLink>
        <NavLink to="/shop" className="link"> 跳转 Shop 页面 </NavLink>   {/* 点击,跳转到 /shop,但该门路没有设置 */}

        <Switch>
          <Route path="/home" component={Home}/>       
          <Route path="/about" component={About}/>      
          <Redirect to="/home" />    {/* 当以上 Route 组件都匹配失败时,重定向到 /home */}                    
        </Switch>

      </Router>
    </div>
  );
}

export default App;

成果如下:

路由传参

所有路由传递的参数,都会在跳转路由组件的 props 中获取到,每种传参形式接管的形式略有不同

路由传参的形式一共有三种,顺次来看一下

第一种

第一种是在 Link 组件的跳转门路上携带参数,并在 Route 组件的匹配门路上通过 : 参数名 的形式接管参数,代码如下:

import { 
  BrowserRouter as Router, 
  Route, 
  NavLink,
  Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        {/* 在 /home 的门路上携带了 张三、18 共两个参数 */}
        <NavLink to="/home/ 张三 /18" className="link"> 跳转 Home 页面 </NavLink>   
        <NavLink to="/about" className="link"> 跳转 About 页面 </NavLink>

        <Switch>
          {/* 在 /home 匹配门路上雷同的地位接管了 name、age 两个参数 */}
          <Route path="/home/:name/:age" component={Home}/>       
          <Route path="/about" component={About}/>                           
        </Switch>

      </Router>
    </div>
  );
}

export default App;

尝试跳转,并打印一下路由组件的 props

能够看到,第一种形式的参数是通过 props.match.params 来获取的

第二种

第二种形式就是通过在 Link 组件的跳转链接前面跟上以 ? 结尾,相似 ?a=1&b=3 这样的参数进行传递,代码如下:

import { 
  BrowserRouter as Router, 
  Route, 
  NavLink,
  Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        {/* 在跳转门路前面以? 结尾传递两个参数,别离为 name= 张三、age=18 */}
        <NavLink to="/home?name= 张三 &age=18" className="link"> 跳转 Home 页面 </NavLink>   
        <NavLink to="/about" className="link"> 跳转 About 页面 </NavLink>

        <Switch>
          {/* 此处无需做接管操作 */}
          <Route path="/home" component={Home}/>       
          <Route path="/about" component={About}/>                           
        </Switch>

      </Router>
    </div>
  );
}

export default App;

尝试跳转,并打印一下路由组件的 props

能够看到,第二种形式的参数是通过 props.location.search 来获取的,不过这里的参数须要本人简略做进一步转化,这里就不做过多阐明了

第三种

第三种形式就是以 对象 的模式编写 Link 组件的 to 跳转属性,并通过 state 属性来传递参数,代码如下:

import { 
  BrowserRouter as Router, 
  Route, 
  NavLink,
  Switch,
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        {/* 以对象的模式形容 to 属性,门路属性名为 pathname,参数属性名为 state */}
        <NavLink to={{pathname: "/home", state: {name: '张三', age: 18}}} className="link"> 跳转 Home 页面 </NavLink>   
        <NavLink to="/about" className="link"> 跳转 About 页面 </NavLink>

        <Switch>
          {/* 此处无需顺便接管属性 */}
          <Route path="/home" component={Home}/>       
          <Route path="/about" component={About}/>                           
        </Switch>

      </Router>
    </div>
  );
}

export default App;

尝试跳转,并打印一下路由组件的 props

能够看到,第三种形式的参数是通过 props.location.state 来获取的

函数式路由

以上次要都是通过 react-router-dom 中的 Link 组件来往某个路由组件跳转

但有时,咱们须要更灵便的形式进行跳转路由,例如通过调用一个函数,随时随地进行路由跳转,这就叫 函数式路由

函数式路由用到的办法有以下 5 个(下方截图来自 路由组件 props

5 个办法别离是 pushreplacegoForwardgoBackgo,接下来按程序介绍一下这几个办法

push

push 办法就是使页面跳转到对应门路,并在浏览器中留下记录(即能够通过浏览器的回退按钮,返回上一个页面)

举个例子:在路由组件 Home 中设置一个按钮 button,点击后调用 push 办法,跳转到 /about 页面

import React from 'react'

function Home (props) {let pushLink = () => {props.history.push('/about')
    }
    
    return (
        <div className="a">
            我是 Home 页面
            <button onClick={pushLink}> 跳转到 about 页面 </button>
        </div>
    )
}

export default Home

跳转成果如下:

能够看到,通过 push 办法跳转当前,能够通过浏览器的回退按钮,返回上一个页面

replace

replace 办法与 push 办法相似,不一样的中央就是,跳转后不会在浏览器中保留上一个页面的记录(即无奈通过浏览器的回退按钮,返回上一个页面)

改变一下代码

import React from 'react'

function Home (props) {let replaceLink = () => {props.history.replace('/about')
    }
    
    return (
        <div className="a">
            我是 Home 页面
            <button onClick={replaceLink}> 跳转到 about 页面 </button>
        </div>
    )
}

export default Home

跳转成果如下:

能够看到,刚开始的门路是 ‘/’,而后跳转到 ‘/home’,再点击按钮,通过 replace 办法跳转到 /about 页面。最初通过浏览器的回退按钮返回到了 / 页面,阐明两头的 /home 没有被存在浏览器的记录里

goForward

调用 goForward 办法,就相当于点击了浏览器的返回下一个页面按钮,如下图所示:

这里就不做过多演示了

goBack

调用 goBack 办法,就相当于点击了浏览器的返回上一个页面的按钮,如下图所示:

go

go 办法顾名思义,是用于跳转到指定门路的。

该办法承受一个参数(参数类型为 Number),状况如下:

  1. 当参数为负数 n 时,示意跳转到下 n 个页面。例如 go(1) 相当于调用了一次 goForward 办法
  2. 当参数为正数 n 时,示意跳转到上 n 个页面。例如 go(-3) 相当于调用了三次 goBack 办法
  3. 当参数为 0 时,示意刷新以后页面

一般组件应用路由

这里辨别两个概念,别离为 一般组件 路由组件

通过 Route 组件渲染的组件为 路由组件 ,其余的基本上都为 一般组件

例如,下方代码中:Home 组件为 路由组件 ; App 组件为 一般组件

import {
  BrowserRouter as Router, 
  Route, 
  NavLink,
  Switch,
} from 'react-router-dom'
import Home from './home'

export default function App() {
  
  return (
    <div className="App">
      <Router>
        <NavLink to='/home' className="link"> 跳转 Home 页面 </NavLink>   

        <Switch>
          <Route path="/home" component={Home}/>                              
        </Switch>

      </Router>
    </div>
  );
}

而后,路由组件跟一般组件最大的区别就是,组件的 props 属性中是否有下图所示的内容:(前者有,后者无)

此时,react-router-dom 提供了一个 withRouter 办法,能够使一般组件也能像路由组件一样有那些办法或数据能够应用

应用办法如下:

import { 
  BrowserRouter as Router, 
  Route, 
  NavLink,
  Switch,
  withRouter,  // 1. 引入 witRouter
} from 'react-router-dom'
import About from './about'

function App(props) {console.log(props);   // 3. 尝试打印一般组件 App 的 props,发现此时 props 中已有内容了,即一般组件也能领有跟路由组件一样相似的性能

  return (
    <div className="App">
      <Router>
        <NavLink to="/about" className="link"> 跳转 About 页面 </NavLink>

        <Switch>
          <Route path="/about" component={About}/>                           
        </Switch>

      </Router>
    </div>
  );
}

export default withRouter(App);  // 2. 通过 withRouter 办法对一般组件做一层包装解决

补充

replace

在函数式路由里跳转类型次要有两种,别离是 pushreplace,那么在非函数式路由中,同样也能够自定义跳转类型,具体的实现代码如下:

import { 
    BrowserRouter as Router, 
    Route, 
    Link 
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {
  return (
    <div className="App">
      <Router>
        <Link to="/home" className="link"> 跳转 Home 页面 </Link>
        <Link to="/about" className="link"> 跳转 About 页面 </Link>

        <Route path="/home" component={Home} replace={true}/>  {/* replace 为 true,跳转类型为 replace */}
        <Route path="/about" component={About} replace={false}/>   {/* replace 为 false,跳转类型为 push */}
      </Router>
    </div>
  );
}

export default App;
Route` 组件上有个 `replace` 属性能够设定跳转类型,当值为 `true` 时,跳转类型为 `replace` ; 为 `false` 时,跳转类型为 `push

excat

路由的匹配默认是 含糊匹配 的,举个例子:

import { 
  BrowserRouter as Router, 
  Route, 
  Link,
} from 'react-router-dom'
import Home from './home'
import About from './about'

function App() {

  return (
    <div className="App">
      <Router>
        <Link to="/home/abc"> 跳转 Home 页面 </Link>    {/* 跳转到 /home/abc,但理论 home 下没有 abc 这个路由组件 */}
        <Link to="/about/abc"> 跳转 About 页面 </Link>  {/* 跳转到 /about/abc,但理论 home 下也没有 abc 这个路由组件 */}

        <Route path="/home" component={Home} />    {/* 路由匹配规定为 /home,没有设置 exact 属性,以后为含糊匹配 */}
        <Route path="/about" component={About} exact/>   {/* 路由匹配规定为 /about,设置了 exact 属性,以后为精准匹配 */}

      </Router>
    </div>
  );
}

export default App;

成果如下:

图中看出,因为跳转 /home/abc 时,第一个 Route 组件是含糊匹配的,所以先匹配到了 /home,因而 Home 组件渲染了 ; 而跳转 /about/abc 时,第二个 Route 组件是精准匹配的,即 /about/abc 不等于 /about,所以 About 组件也没有渲染

总结:

  1. 如果想要精准匹配的话,只须要将 Route 组件的 exact 属性设置为 true 即可
  2. 精准匹配要审慎应用,因为可能会影响嵌套路由的应用
退出移动版