React路由

React路由react路由规则,编程式导航,匹配模式,传递参数等

大家好,又见面了,我是你们的朋友全栈君。

react路由

现代的前端应用大多都是SPA(单页应用程序),也就是只有一个HTML页面的应用程序。因为它的用户体验更好、对服务器的压力更小,所以更受欢迎。为了有效的使用单个页面来管理原来多页面的功能,前端路由应运而生

前端路由的功能:让用户从一个视图(页面)导航到另一个视图(页面),前端路由是一套映射规则,在Reat中是URL路径与组件的对应关系,使用 React路由简单来说,就是配置路径和组件(配对)。

文档:https://react-router.docschina.org/web/guides/philosophy

react路由的基本使用

  1. 安装:npm i react-router-dom
  2. 导入路由的三个核心组件,它们是组件
import { 
    BrowserRouter as Router, Route, Link } from "react-router-dom";
  1. 使用Router组件包裹整个应用
  2. 使用Link组件作为导航菜单(路由入口)
  3. 使用Route组件配置路由规则和要展示的组件(路由出口)
import React from 'react'
import ReactDom from 'react-dom'

// 导入路由组件
import { 
    BrowserRouter as Router, Route, Link } from "react-router-dom";

const App = () => (
  // 使用Router组件包裹整个应用
  <Router>
    <div>
      <h1>react</h1>

      { 
   /* 指定路由入口 */}
      <Link to="/first">页面1</Link>
      <Link to="/second">页面2</Link>

      { 
   /* 指定路由出口,path设置为Link中的to属性,component设置为要渲染的组件 */}
      <Route path="/first" component={ 
   First}></Route>
      <Route path="/second" component={ 
   Second}></Route>
    </div>
  </Router>
)

class First extends React.Component { 
   
  render() { 
   
    return (
      <div>
        <h2>我是页面1的标题</h2>
      </div>
    )
  }
}

const Second = () => (
  <div>
    <h2>我是页面2</h2>
  </div>
)


ReactDom.render(<App />, document.getElementById('root'));

常用组件说明

BrowserRouter和HashRouter组件

  • BrowserRouter或HashRouter组件:包裹整个应用,一个 React应用只需要使用一次
    • HashRouter:使用URL的哈希值实现( localhost:3000/#/first)
    • BrowserRouter:使用H5的 history Api实现( localhost:3000/first)
import { 
    BrowserRouter, Route, Link } from "react-router-dom";

import { 
    HashRouter, Route, Link } from "react-router-dom";

在这里插入图片描述

hash模式下#后边的路径不会发给服务器,不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面,在处理相对路径方面的一些问题时,使用HashRouter可以解决。

Link组件

Link组件:用于指定导航链接,默认会被渲染为一个a标签,Link组件的to属性会作为href值

<Link to="/first">页面1</Link>

<a href="/first">页面1</a>

Route组件

Route组件:指定路由展示的组件(注册路由)

  • path属性:路由规则
  • component属性:指定当路由匹配时要展示的组件
  • Route组件写在哪,渲染出来的组件就展示在哪
<Route path="/first" component={ 
   First}></Route>

如果没有path属性,将匹配所有的路径。

NavLink组件

NavLink可以实现路由链接的高亮,通过activeClassName指定样式名。当点击哪个导航链接,哪个导航菜单就会应用activeClassName指定的样式。

对NavLink再做一层封装

import React, { 
    Component } from 'react'
import { 
    NavLink } from 'react-router-dom'

export default class MyNavLink extends Component { 
   
  render() { 
   
    console.log(this.props)
    return <NavLink activeClassName="active" { 
   ...this.props}></NavLink>
  }
}

使用

<MyNavLink to="/home" children="home" />
<MyNavLink to="/about" children="about" />

Switch组件

默认情况下,在匹配到一个路由后会继续往下匹配。比如下方代码,在/home路径匹配到Home组件的情况下,依然会继续往下匹配到Test组件
在这里插入图片描述
在这里插入图片描述

但是一个路由一般只对应一个组件,在已经匹配到的情况下就没有必要继续往下匹配了。此时可以使用Switch组件,Switch可以提高路由匹配效率(单一匹配)

import { 
    Route, Switch } from 'react-router-dom'

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

Routes组件

注意!!!在 react-router-dom的6.x版本中,“Switch”被替换为了“Routes”,需要更新导入语句

import { 
    Switch, Route } from "react-router-dom";

// 更新为
import { 
    Routes ,Route } from 'react-router-dom';

同时需要更新Route的声明语句

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

// 更新为
<Route path='/welcome' element={<Home/>} />

Redirect组件

一般写在所有路由注册的最下方, 当所有路由都无法匹配时,跳转到Redirect指定的路由

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

from属性和to属性

  1. Switch中是Route 从上到下匹配,如果有一个匹配,后面的就不会再继续匹配了
  2. Redirect的from属性是当地址与from匹配(可以用正则)时,才会重定向到to属性指定的路径
  3. Redirect的from属性如果没有,则默认是匹配所有的路径

exact

完全匹配 from;相当于 Route.exact

strict

严格匹配 from;相当于 Route.strict

路由组件和一般组件

  1. 写法不同

一般组件: <Demo/>
路由组件: <Route path=" /demo" component={Demo}/>

  1. 存放位置不同

一般组件:components
路由组件:pages

  1. 接收到的props不同

一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性
在这里插入图片描述

路由的执行过程

  1. 点击Link组件(a标签)会修改浏览器地址栏中的url
  2. React路由监听到地址栏url的变化。
  3. Reat路由内部遍历所有 Route组件,使用路由规则(path)与 pathname进行匹配
  4. 当路由规则(path)能够匹配地址栏中的pathname时,就展示渲染该 Route组件的内容

在这里插入图片描述

编程式导航

  • 编程式导航:通过JS代码来实现页面跳转
  • history是 React路由提供的,用于获取浏览器历史记录的相关信息。借助props.history对象上的API进行跳转。**只有路由组件的props上才有history对象,**普通组件的props上的history是undefined。
  • push(path):跳转到某个页面,参数path表示要跳转的路径
  • go(n):前进或后退到某个页面,参数n表示前进或后退页面数量(比如:-1表示后退到上一页)

为什么是从props上拿到history对象呢?我们创建的组件是没有history对象的,在Route组件中渲染了自己创建的组件,然后通过prop传了history进去。组件就可以通过props拿到history

import React from 'react'
import ReactDom from 'react-dom'

// 导入路由组件
import { 
    BrowserRouter as Router, Route, Link } from "react-router-dom";
// import { HashRouter as Router, Route, Link } from "react-router-dom";

class App extends React.Component { 
   
  render() { 
   
    return (
      <Router>
        <div>
          <p>编程式导航</p>
          <Link to="/login">去登录页面</Link>

          <Route path="/login" component={ 
   Login}></Route>
          <Route path="/home" component={ 
   Home}></Route>
        </div>
      </Router>
    )
  }
}

class Login extends React.Component { 
   

  handleLogin = () => { 
   
    this.props.history.push("/home");
  }

  render() { 
   
    return (
      <div>
        <h1>登录界面</h1>
        <button onClick={ 
   this.handleLogin}>首页</button>
      </div>
    )
  }
}


const Home = (props) => { 
   
  const goBack = () => { 
   
    props.history.go(-1);
  }

  return (
    <div>
      <h2>首页</h2>
      <button onClick={ 
   goBack}>返回</button>
    </div>
  )
}

ReactDom.render(<App />, document.getElementById('root'));

withRouter

一般组件的props上的history是undefined,无法使用编程式导航的api。此时可以用withRouter函数。

  • withRouter是一个函数,可以加工一般组件,让一般组件具备路由组件所特有的API,通过props传递三个属性:history/location/match
  • withRouter的返回值是一个新组件
import React, { 
    Component } from 'react'
import { 
    withRouter } from 'react-router-dom'

// Header是一般组件
class Header extends Component { 
   
  back = () => { 
   
    this.props.history.goBack()
  }

  forward = () => { 
   
    this.props.history.goForward()
  }

  go = () => { 
   
    this.props.history.go(2)
  }

  render() { 
   
    console.log('Header组件中的props:', this.props)
    return (
      <div className="head">
        <h1>React-router-dom</h1>
        <button onClick={ 
   this.back}>回退</button>
        <button onClick={ 
   this.forward}>前进</button>
        <button onClick={ 
   this.go}>go</button>
      </div>
    )
  }
}

// withRouter是一个函数,可以加工一般组件,让一般组件具备路由组件所特有的API
// withRouter的返回值是一个新组件
export default withRouter(Header)

默认路由

默认路由表示进入到页面后就能匹配到的路由,并展示对应的组件

<Route path="/" component={ 
   Login}></Route>

匹配模式

模糊匹配模式

  • 默认情况下, React路由是模糊匹配模式
  • 模糊匹配规则:只要pathname以path开头就会匹配成功,对应的组件就会被渲染出来
    • path代表Route组件的path属性
    • pathname代表Link组件的to属性(也就是location.pathname)
      在这里插入图片描述

精确匹配

  • 给 Route组件添加exact属性,让其变为精确匹配模式
  • 精确匹配:只有当path和 pathname完全匹配时才会展示该路由

严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

class App extends React.Component { 
   
  render() { 
   
    return (
      <Router>
        <div>
          <Link to="/">首页</Link>
          

          <Link to="/login">登录页面</Link>

          { 
   /* 此时该组件只会匹配"/"这一种情况 */}
          <Route path="/" exact component={ 
   Home}></Route>
          <Route path="/login" component={ 
   Login}></Route>
        </div>
      </Router>
    )
  }
}

push和replace模式

默认情况下,路由的切换是push模式,点击后退按钮时还可以回到上一个路由。如果想要开启replace模式,需要在Link组件上添加replace属性

<Link to="/home" replace></Link>

嵌套路由

  1. 注册子路由时要写上父路由的path值
  2. 路由的匹配是按照注册路由的顺序进行的

向路由组件传递参数

params参数

在这里插入图片描述

import React, { 
    Component } from 'react'
import { 
    Link, Route } from 'react-router-dom'
import Detail from './Detail'

export default class Message extends Component { 
   
  state = { 
   
    messageArr: [
      { 
   
        id: 1,
        title: '消息1',
      },
      { 
   
        id: 2,
        title: '消息2',
      },
      { 
   
        id: 3,
        title: '消息3',
      },
    ],
  }

  render() { 
   
    return (
      <div>
        <ul>
          { 
   this.state.messageArr.map((msgObj) => { 
   
            return (
              <li key={ 
   msgObj.id}>
                { 
   /* 1、向路由组件传递params参数 */}
                <Link to={ 
   `/home/message/detail/${ 
     msgObj.id}/${ 
     msgObj.title}`}>
                  { 
   msgObj.title}
                </Link>
              </li>
            )
          })}
        </ul>
        
        { 
   /* 2、声明接受params参数 */}
        <Route path="/home/message/detail/:id/:title" component={ 
   Detail} />
      </div>
    )
  }
}

接收params参数

import React, { 
    Component } from 'react'

const detailData = [
  { 
    id: 1, content: '内容1' },
  { 
    id: 2, content: '内容2' },
  { 
    id: 3, content: '内容3' },
]
export default class Detail extends Component { 
   
  render() { 
   
    console.log('detail:', this.props)
    // 接收params参数
    const { 
    id, title } = this.props.match.params
    let index = parseInt(id) - 1
    return (
      <ul>
        <li>id:{ 
   id}</li>
        <li>title:{ 
   title}</li>
        <li>content:{ 
   detailData[index].content}</li>
      </ul>
    )
  }
}

在这里插入图片描述

search参数

在这里插入图片描述

import React, { 
    Component } from 'react'
import { 
    Link, Route } from 'react-router-dom'
import Detail from './Detail'

export default class Message extends Component { 
   
  state = { 
   
    messageArr: [
      { 
   
        id: 1,
        title: '消息1',
      },
      { 
   
        id: 2,
        title: '消息2',
      },
      { 
   
        id: 3,
        title: '消息3',
      },
    ],
  }
  render() { 
   
    return (
      <div>
        <ul>
          { 
   this.state.messageArr.map((msgObj) => { 
   
            return (
              <li key={ 
   msgObj.id}>
                { 
   /* 1、向路由组件传递search参数 */}
                <Link to={ 
   `/home/message/detail?id=${ 
     msgObj.id}&title=${ 
     msgObj.title}`}>
                  { 
   msgObj.title}
                </Link>
              </li>
            )
          })}
        </ul>
        
        { 
   /* 2、search参数无须声明接收,正常注册路由即可 */}
        <Route path="/home/message/detail" component={ 
   Detail} />
      </div>
    )
  }
}

接收参数

import React, { 
    Component } from 'react'
import qs from 'querystring'

let obj = { 
    id: 1, name: 'mingming' }
console.log(qs.stringify(obj)) // id=1&name=mingming 这是urlencoded格式
let query = 'id=1&name=mingming'
console.log(qs.parse(query)) // {id: "1", name: "mingming"}

const detailData = [
  { 
    id: 1, content: '内容1' },
  { 
    id: 2, content: '内容2' },
  { 
    id: 3, content: '内容3' },
]
export default class Detail extends Component { 
   
  render() { 
   
    console.log('detail:', this.props)

    // 3、接收search参数
    const { 
    id, title } = qs.parse(this.props.location.search.slice(1))
    let index = parseInt(id) - 1
    return (
      <ul>
        <li>id:{ 
   id}</li>
        <li>title:{ 
   title}</li>
        <li>content:{ 
   detailData[index].content}</li>
      </ul>
    )
  }
}

在这里插入图片描述

state参数

在这里插入图片描述

import React, { 
    Component } from 'react'
import { 
    Link, Route } from 'react-router-dom'
import Detail from './Detail'

export default class Message extends Component { 
   
  state = { 
   
    messageArr: [
      { 
   
        id: 1,
        title: '消息1',
      },
      { 
   
        id: 2,
        title: '消息2',
      },
      { 
   
        id: 3,
        title: '消息3',
      },
    ],
  }
  render() { 
   
    return (
      <div>
        <ul>
          { 
   this.state.messageArr.map((msgObj) => { 
   
            return (
              <li key={ 
   msgObj.id}>
                { 
   /* 1、向路由组件传递state参数 */}
                <Link
                  to={ 
   { 
   
                    pathname: '/home/message/detail',
                    state: { 
    id: msgObj.id, title: msgObj.title },
                  }}>
                  { 
   msgObj.title}
                </Link>
              </li>
            )
          })}
        </ul>
        
        { 
   /* 2、state参数无须声明接收,正常注册路由即可 */}
        <Route path="/home/message/detail" component={ 
   Detail} />
      </div>
    )
  }
}

接收参数

import React, { 
    Component } from 'react'

const detailData = [
  { 
    id: 1, content: '内容1' },
  { 
    id: 2, content: '内容2' },
  { 
    id: 3, content: '内容3' },
]

export default class Detail extends Component { 
   
  render() { 
   
    console.log('detail:', this.props)
		
    // 接收state参数
    // 如果清空history对象或者清除浏览器的历史记录,此时刷新页面会报错state是undefined
    const { 
    id, title } = this.props.location.state || { 
   }
    let msgObj = detailData.find((item) => item.id === id) || { 
   }
    return (
      <ul>
        <li>id:{ 
   id}</li>
        <li>title:{ 
   title}</li>
        <li>content:{ 
   msgObj.content}</li>
      </ul>
    )
  }
}

编程式导航传递参数

pushShow = (msgObj) => { 
   
  // 传递params参数
  this.props.history.push(`/home/message/detail/${ 
     msgObj.id}/${ 
     msgObj.title}`)

  // 传递search参数
  this.props.history.push(`/home/message/detail?id=${ 
     msgObj.id}&title=${ 
     msgObj.title}`)

  // 传递state参数
  this.props.history.push(`/home/message/detail`, { 
   
    id: msgObj.id,
    title: msgObj.title,
  })
}

前端学习交流QQ群,群内学习讨论的氛围很好,大佬云集,期待你的加入:862748629点我加入

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/130933.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql是什么类型数据库_MySQL是一种

    mysql是什么类型数据库_MySQL是一种在学习MySQL之前,首先需要了解数据库和SQL。如果您已经知道数据库和SQL,那么可以直接跳转到下一章节的学习。1.数据库简介当您想收听最喜欢的歌曲时,可以从智能手机上打开播放列表。在这种情

    2022年8月1日
    3
  • Java获取的一天、本星期、这个月、本季度、一年等 开始和结束时间

    Java获取的一天、本星期、这个月、本季度、一年等 开始和结束时间

    2022年1月2日
    42
  • 主流量化交易的几种策略模型

    主流量化交易的几种策略模型量化策略可以简单分为三类,分别是Alpha策略、CTA策略以及高频交易策略1.Alpha策略Alpha策略包含不同类别:按照研究内容来分,可分为基本面Alpha(或者叫财务Alpha)和量价Alpha。业内普遍不会将这两种Alpha完全隔离开。但是不同团队会按照其能力、擅长方向以及信仰,在做因子上有所偏向。有的团队喜欢用数据挖掘的方式做量价因子,而有的团队喜欢从基本面财务逻辑的角度出发,精细地筛选财务因子。。按照是否对冲可以分为两类。全对冲的叫做Alpha策略,不对冲的在市面上常被称作指

    2022年6月26日
    39
  • 【Anconda】关于安装Anaconda3各种各样的问题,吐血总结!!!(failed to create anacoda menu!!++)「建议收藏」

    【Anconda】关于安装Anaconda3各种各样的问题,吐血总结!!!(failed to create anacoda menu!!++)「建议收藏」昨天总结了装python和pycharm。本来想着马上接着总结Anaconda的,谁知道,这一安装,竟然花了我一天一夜的时间,(悲伤辣么大啊简直)。遇到了各种各样的问题,重装20几遍,每次问题都不同还。(掩面悲伤)直到刚才总算是可以了。面对问题的时候第一想法就是百度,结果尝试了所有百度的方法仍然无法解决问题。还是自己太笨了。总之,还是把自己遇到的问题总结一下把,以防不…

    2022年6月2日
    84
  • 微博用户洞察_实现一个观察者模式

    微博用户洞察_实现一个观察者模式观察者模式:当对象间存在一对多关系时,则使用观察者模式(ObserverPattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。观察者模式定义了对象间的一种

    2022年8月6日
    3
  • 如何判断一个数是否为素数(判断一个数为素数)

    目录1.什么是质数?2.如何判断是否为质数?方法1方法2方法3方法41.什么是质数?首先来看质数的概念:质数(Primenumber),又称素数,指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数。(也可定义为只有1与该数本身两个正因数的数)图1数字12不是质数,而数字11是质数如上图所示,数字12可以将每4个分成一组,…

    2022年4月18日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号