React笔记(七) React路由

React笔记(七)

1.React路由理解
  • React实现的是SPA应用,即单页Web页面,整个应用中只有一个完整的页面,点击页面中的链接也不会刷新页面,只会对页面进行局部的刷新。因此在更换页面时需要使用路由实现。

  • 路由就是一个键值对映射关系,键为访问路径,值为函数或者是组件,后端路由代表的是函数,用来处理不同的请求,前端路由代表的则是组件或页面,通过路径的不同,展示不同的页面内容。下面的这两个路径就代表了不同的页面。通过改变链接路径,来显示不同内容。

    https://blog.csdn.net/nav/web

    https://blog.csdn.net/nav/back-end

2.React-Router5基本使用
  • React内不提供内置的路由,但是可通过一个插件来完成react路由的使用。首先安装react-router-dom插件库。并进行使用。

  • 在需要路由切换时,可以从下载的插件库中引入Link组件。代表着路由链接,实现组件切换。并且还需要将想要切换的路由组件注册在BrowserRouter组件(代表着浏览器的路由)或者HashRouter组件(使用锚点路由)内。

    // 引入BrowserRouter:路由;Link:跳转;Route:路由组件
    import { BrowserRouter, Link, Route } from 'react-router-dom'
    
    export default function DemoR(props) {
      console.log('render');
      // 在最外侧用路由组件包裹住,在实际开发中推荐在App.jsx中包裹住。
      return <BrowserRouter>
      <div>
        {/* 点击link路由跳转,相当于HTML中的a标签 */}
        <Link to='/A'>点我看页面A</Link>
        <br/>
        <Link to='/B'>点我看页面B</Link>
      </div>
        {/* 将组件注册进路由,创建路径与组件的映射关系,component内放置组件,path内放置路径 */}
        <Route component={RouteA} path='/A'/>
        <Route component={RouteB} path='/B'/>
      </BrowserRouter>
    }
    
    // 需要注册进路由的组件
    function RouteA(props){
      console.log(props);
      return <p>我是页面A</p>
    }
    
    function RouteB(){
      return <p>我是页面B</p>
    }
    

    在上面示例中,通过点击了链接可以达到切换页面的效果,并且值得注意的是,主页面只进行了一次渲染(可以通过查看控制台来判断),并且页面的路径也随着点击而更改。

    在这里插入图片描述
    在这里插入图片描述

  • 注册进路由的组件相对于一般组件,其存在着一定的区别

    • 一般组件在使用时,直接引入组件对应的标签即可。而路由组件则需要将组件引入<Route component={组件名} path='路径'/>中的组件名处。

    • 一般组件接收到的props是父组件传递了什么,子组件就会接收到什么。而路由组件中会接收到三个特定的属性,而这三个属性将在路由传值处尤为重要。

      {
          //浏览器的历史信息,包含有路由如何切换,路径信息等
          "history": {
              "length": 13,
              "action": "PUSH",
              "location": {
                  "pathname": "/A",
                  "search": "",
                  "hash": "",
                  "key": "p3jxy2"
              }
          },
          //当前的路径信息
          "location": {
              "pathname": "/A",
              "search": "",
              "hash": "",
              "key": "p3jxy2"
          },
          //匹配路径参数的对象
          "match": {
              "path": "/A",
              "url": "/A",
              "isExact": true,
              "params": {}
          }
      }
      
  • 相比于父子直接传值,由于注册进路由的组件没有以标签的形式被使用,因此传值与普通的父子传值不同。存在着三种传值方式。

    • params传值,在路由链接中携带参数,并在注册路由时进行声明。当路由组件接收参数时,参数会存在于props.match.params中。这一传值方式的优势是,即使刷新地址栏,参数依然存在;缺点是:只可以传递字符串,并且传值过多时,url会比较长。

    • search传值,类似于get请求中的filter或select参数,其在注册时无需声明。接收到的参数会存在于props.location.search中。在使用时由于是urlencode后的值,因此需要借助querystring进行解析。优缺点同params传值。

    • state传值,在路由链接中携带参数to做为需要传递的对象,注册时也无需声明,接收到的参数会存储在props.location.search中。优点很明显,可以传递对象,缺点则是重新打开页面时,传递的state会丢失,但刷新不会丢失(仅限BrowserRouter)。

      //引入queryString
      const queryString = require('query-string');
      
      export default function DemoR(props) {
        const obj = {
          id:1,
          name:'小明'
        };
        console.log('render');
        return <BrowserRouter>
        <div>
          {/* Params传值跳转方式,形为A/参数1/参数2…… */}
          <Link to={`/A/${obj.id}/${obj.name}`}>点我看页面A</Link>
          <br/>
          {/* Search传值跳转方式,形为A?参数1名=参数1&参数2名=参数2…… */}
          <Link to={`/B/?id=${obj.id}&name=${obj.name}`}>点我看页面B</Link>
          <br/>
          {/* State传值跳转方式,to传递一个pathname与state组成的对象 */}
          <Link to={{pathname:`/C`,state:obj}}>点我看页面C</Link>
        </div>
          {/* Params传值注册方式,形为A/:参数1名/:参数2名…… */}
          <Route component={RouteA} path='/A/:id/:name'/>
          <Route component={RouteB} path='/B'/>
          <Route component={RouteC} path='/C'/>
        </BrowserRouter>
      }
      function RouteA(props){
        // 直接接收传值
        return <>
        <h3>我是页面A,params传值,接收到的参数为</h3>
        <p>id:{props.match.params.id}</p>
        <p>name:{props.match.params.name}</p>
        </>
      }
      
      function RouteB(props){
        // 使用queryString处理后再接收
        var obj = queryString.parse(props.location.search);
        return <>
        <h3>我是页面B,search传值,接收到的参数为</h3>
        <p>id:{obj.id}</p>
        <p>name:{obj.name}</p>
        </>
      }
      
      function RouteC(props){
        // 直接接收传值
        return <>
        <h3>我是页面C,state传值,接收到的参数为</h3>
        <p>id:{props.location.state.id}</p>
        <p>name:{props.location.state.name}</p>
        </>
      }
      
      
  • 在props中存在着action,代表着路由跳转是push行为还是replace行为。push代表着在路由跳转时以添加的方式添加进浏览器的历史中,即点击浏览器的后退按钮会返回上一个页面,默认为push。replace则代表替换掉了上一个页面,点击后退按钮不会返回到上一个页面。

  • 当需要使用嵌套路由时,即多级的路由时,这时可以直接书写双层路由,但要注意的是,注册子路由时需要写上父路由的值,路由的匹配则是按照注册路由的顺序进行的。

    export default function DemoR(props) {
      return <BrowserRouter>
      <div>
        <Link to='/A'>点我显示A页面</Link>
      </div>
        <Route component={RouteA} path='/A'/>
      {/* 定义嵌套子路由 */}
        <Route component={RouteB} path='/A/BChild'/>
        <Route component={RouteC} path='/A/CChild'/>
      </BrowserRouter>
    }
    function RouteA(){
      return <>
      <h3>我是页面A</h3>
      {/* 跳转嵌套子路由 */}
      <Link to='/A/BChild'>点我看B子路由</Link>
      <Link to='/A/CChild'>点我看C子路由</Link>
      </>
    }
    function RouteB(){
      return <h3>我是页面B</h3>
    }
    function RouteC(){
      return <h3>我是页面C</h3>
    }
    
3.React-Router5扩展使用
  • 在使用了link之后,尽管可以实现点击link路由跳转,但是却无法查看当前点击了哪个按钮,如果通过操作state状态来完成按钮样式的更改,也可以实现。但React-Router中存在着一个组件即NavLink,其可以完成显示为当前所在的路由link提供特殊的样式。

    import { BrowserRouter, NavLink, Route } from 'react-router-dom'
    import './Demo.css'
    
    export default function DemoR(props) {
      console.log('render');
      return <BrowserRouter>
      <div>
        {/* 通过为activeClassName赋予特定类名可令其在活性时改变样式 */}
        <NavLink to='/A' className='linkbox' activeClassName='active'>点我看页面A</NavLink>
        {/* 通过为activeStyle赋予特定样式可令其在活性时改变样式 */}
        <NavLink to='/B' className='linkbox' activeStyle={{backgroundColor:'yellow'}}>点我看页面B</NavLink>
      </div>
        <Route component={RouteA} path='/A'/>
        <Route component={RouteB} path='/B'/>
      </BrowserRouter>
    }
    
    function RouteA(props){
      console.log(props);
      return <p>我是页面A</p>
    }
    
    function RouteB(){
      return <p>我是页面B</p>
    }
    
  • 由于React-Router匹配路由时是从头到尾逐个匹配,因此当路由多时,效率减低,因此可以使用Switch将注册的路由组件包裹起来,一旦匹配到后就停止继续匹配,提高效率。但需要注意的是,由于一旦匹配到就停止继续匹配,因此要将父路由放于子路由的下面,因为当父路由一旦匹配上时,就会停止继续匹配,画面显示错误。并且如果需要嵌套时,则需要在父路由组件中用Switch包裹子路由

    export default function DemoR(props) {
      return <BrowserRouter>
      <div>
        <Link to='/A'>点我显示A页面</Link>
      </div>
      <Switch>
        {/* <Route component={RouteB} path='/A/BChild'/>
        <Route component={RouteC} path='/A/CChild'/> */}
        <Route component={RouteA} path='/A'/>
      </Switch>
      </BrowserRouter>
    }
    function RouteA(){
      return <>
      <h3>我是页面A</h3>
      <Link to='/A/BChild'>点我看B子路由</Link>
      <Link to='/A/CChild'>点我看C子路由</Link>
      <Switch>
        <Route component={RouteB} path='/A/BChild'/>
        <Route component={RouteC} path='/A/CChild'/>
      </Switch>
      </>
    }
    function RouteB(){
      return <h3>我是页面B</h3>
    }
    function RouteC(){
      return <h3>我是页面C</h3>
    }
    

    另外,在实际书写时,也可以为特定的Route标签添加exact属性来实现精确匹配(只有路径完全一样才行)。

  • 在路由书写不规范时,想让其跳转到一个默认页,这时可以使用Redirect重定向路由,使用方法为只需要为注册的部分添加<Redirect to='/A'/>,并将其放在所有路由注册的最下方,即可完成重定向。为to属性赋的值为重定向跳往的目标链接。

  • 编程式路由导航可以作为在组件内完成某些事务中,进行页面跳转,又或者是在一般组件内进行页面跳转,这时需要使用到withRouter这个高阶组件来将一般组件转换为路由组件。并且还需要借助于路由组件上props.history的五个方法,go方法代表前几页,replace完成replace方式的路由跳转,push完成push方式的路由跳转,goBack回退函数,goForward前进函数。

    export default function DemoR(props) {
      return <BrowserRouter>
      <div>
        <Link to='/A'>点我显示A页面</Link>
      </div>
      <Switch>
        <Route component={RouteA} path='/A'/>
        <Route component={RouteB} path='/B'/>
        <Redirect to='/A'/>
      </Switch>
      </BrowserRouter>
    }
    function RouteA(){
      return <>
      <h3>我是页面A</h3>
      <RouteC/>
      </>
    }
    function RouteB(){
      return <h3>我是页面B</h3>
    }
    
    // 将一般组件转换为路由组件
    const RouteC = withRouter(ComponentC);
    
    function ComponentC(props){
      // 调用方法进行编程式路由跳转
      return <button onClick={()=>props.history.push('/B')}>点我跳转至页面B</button>
    }
    
4.React-Router6的变化
  • 内置组件移除了<Switch/>标签,新增<Routes/>标签,并且原本注册路由的标签内书写方式也进行了更改,可以为Route标签指定caseSensitive属性来配置匹配时是否区分大小写。

    {/* 原写法 */}
    <Switch>
      <Route path="/A" component={RouteA}>
    </Switch>
    {/* 新写法,去掉component属性,添加element属性,并为其传递标签 */}
    <Routes>
      <Route path="/A" element={<RouteA/>}>
    </Routes>
    
  • 在重定向时写法也进行了一定改变,并可以使用replace属性调节跳转模式。

    {/* 原写法 */}
      <Redirect to='/A'/>
    {/* 新写法,为element属性传递Navigate标签进行重定向,Navigate标签书写方式与原写法相像 */}
    <Route path='/' element={<Navigate to='/A'/>}>
    
  • NavLink高亮样式的设置也进行了更改。通过一个回调函数进行设置

    <NavLink to='/A' className={(isActive)=>{return isActive?'active link':'link'}}>点我看页面A</NavLink>
    
  • 允许使用useRoutes方法加载路由表。并可以将嵌套路由配置在父路由的Children属性中。

  • 在三种传值方式中,可以分别使用useParamsuseSearchParamsuseLocation进行解构赋值,获取到传给路由组件的值。

  • 可以使用useNavigate进行编程式路由导航,其具备两个参数,第一个参数为目标链接地址,第二个参数为配置项目,包含有替换模式与State。

参考文章

最新 React Router 全面整理 - 知乎 (zhihu.com)

React路由传参 - 简书 (jianshu.com)

React中的路由react-router - 简书 (jianshu.com)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值