React路由

news2025/1/19 17:13:37

文章目录

  • 单页面应用spa
  • 路由
    • 路由是什么
    • React路由原理
      • 点击页面选项路径改变
      • 路径改变页面变化
    • React路由的使用
      • 实现点击页面选项路径改变——编写路由链接
      • 根据路径显示组件 ——注册路由
      • 组件的分类——普通组件和路由组件
      • 案例
      • 实现选中高亮效果——NavLink
      • NavLink的封装
      • Switch的使用
      • 补充:样式丢失问题
        • 解决·:
      • 路由的严格匹配与模糊匹配
        • 模糊匹配
        • 严格匹配
    • Redirect重定向的使用
    • 嵌套路由
    • 路由传参
      • 向路由组件传递params参数
        • 使用方法
        • 例子
      • 向路由组件传递search参数(query参数)
        • 补充:qs库
        • 使用方式
        • 例子
      • 向路由组件传递state参数
        • 使用方式
        • 例子
    • 路由的两种模式push与replace
    • 编程式路由导航
    • withRouter的使用(一般组件实现编程式路由导航)
    • BrowserRouter 和 HashRouter的区别

单页面应用spa

多页面应用是指每切换一个页面就是一个真正的html页面。
单页面应用是指整个应用只有一个完整的页面,点击页面中的链接不会刷新页面只会局部更新,并且数据都需要通过ajax请求获取,并在前端异步展示。

单页面,多组件。

路由

路由是什么

  1. 什么是路由? —— Route
    —个路由就是一个映射关系 ( key:value )
    key为路径, value 可能是function(后端路由)或component(前端路由)路由分类
  • 后端路由:
    理解:value是function,用来处理客户端提交的请求。
    注册路由: router.get(path, function(req, res))
    工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路
    由中的函数来处理请求返回响应数据
  • 前端路由:
    浏览器端路由,value是component,用于展示页面内容。
    注册路由: <Route path="/test" component={Test}>
    工作过程:当浏览器的path变为/test时,当前路由组件就会变为Test组件
  1. 路由器 —— Router
    路由器是用于管理路由的。

React路由原理

在这里插入图片描述
路由匹配的是只是端口号后面的内容(/about、/history)。

点击页面选项路径改变

那么是如何实现一点击导航栏的选项浏览器地址栏中的路径就改变呢, 这就需要借助history实现。
浏览器的BOM身上有一个history,用于管理浏览器的路径、历史记录等。
但是BOM原生的history不好操作我们一般用一个封装好的库history.js,(该库实际上操作的也是BOM身上的history)引入:

<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>

,使用:

  1. 引入:
let history = History.createBrowserHistory()
  1. 推入
// 将路径放到历史记录history中
	history.push(path)
  1. 替换
// 将路径放到历史记录history中
	history.replace(path)
  1. 监听路径变化
// history的listen方法可以监听路径的修改
	history.listen((location) => {
		console.log('请求路由路径变化了', location)
	})
  1. 前进
	history.goForward()
  1. 后退
	history.goBack()

history的数据结构是栈结构:
在这里插入图片描述
栈顶的路径就是当前页面显示的内容。

History.createBrowserHistory()是使用的是h5身上的history方法,在某些旧的浏览器不支持。
可以使用: History.createHashHistory(),和createBrowserHistory的区别是路径中会多出一个 # ,虽然不好看但是兼容性特别好。

History.createBrowserHistory():

在这里插入图片描述

History.createHashHistory():

在这里插入图片描述

路径改变页面变化

React会监听路径,当路径发生变化时,被前端路由器检测到,就会进行路由匹配重新渲染页面。

React路由的使用

React路由的实现需要借助react的路由插件库:react-router-dom, 专门用于实现SPA应用。

  • 安装:
npm i react-router-dom

实现点击页面选项路径改变——编写路由链接

直接利用从 react-router-dom 库中引入的路由器Router</Link>标签就可以实现:

import { BrowserRouter, Link } from 'react-router-dom'

<BrowserRouter>
    <Link className="list-group-item" to="/about">About</Link>
    <Link className="list-group-item" to="/home">Home</Link>
 </BrowserRouter>

点击About浏览器的路径就变成 /about, 点击Home浏览器的路径就变成/home

有两种Router标签:<BrowserRouter> 和 <HashRouter>,在Router标签中再使用<Link>进行路由。
<BrowserRouter> 标签就对应history的browser模式
<HashRouter> 标签就对应history的hash模式

(最后在浏览器渲染的时候,Link标签实际上是会转换为a标签的)

根据路径显示组件 ——注册路由

直接利用从 react-router-dom 库中引入的路由Route 进行路由的注册:

   import { Route } from 'react-router-dom'
{/* 注册路由 */}
  	<Route path="/about" component={About}/>
    <Route path="/home" component={Home}/>

<Route > 也需要使用Router标签进行包裹,但是编写路由链接的路由器应该和注册路由的路由器是一个路由器才对,可以直接将<App/>组件使用Router标签包裹即可。

index.js

// 引入react核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入路由组件
import { BrowserRouter } from 'react-router-dom'
// 引入App组件
import App from './App'

// 渲染App到页面
ReactDOM.render(
   <BrowserRouter>
       <App/>
   </BrowserRouter>, 
   document.getElementById('root'))

组件的分类——普通组件和路由组件

像上面的例子通过路由来使用组件:<Route path="/about" component={About}/>,这样的组件叫做路由组件。还有一类就是通过标签正常使用的组件如<About/>,这样的组件就是普通组件。
普通组件一般直接放在src/component文件夹中,路由组件一般放在src/pages中。

普通组件和路由组件一个最大的区别就是,路由组件可以接收到路由器传递的参数。如当点击上述例子的About按钮时,接收到的参数为:
在这里插入图片描述

  • history :
    go:可以穿参数n,表示前进或后退|n|步,n>0表示前进n步,n<0表示后退n步。
    goBack:后退1步
    goForward:前进1步
    push:push路由
    replace:replace路由
    location:(和下面的这个location是同一个对象)
  • location
    pathname:获取路由路径
    search:(存储swarch参数)
    state:(存储state参数)
  • match
    params:(存储params参数)
    path:获取路由路径
    url:获取路由路径

案例

实现效果:
在这里插入图片描述
在这里插入图片描述
代码:

在这里插入图片描述
src/index.js

// 引入react核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入路由组件
import { BrowserRouter } from 'react-router-dom'
// 引入App组件
import App from './App'

// 渲染App到页面
ReactDOM.render(
    <BrowserRouter>
        <App/>
    </BrowserRouter>, document.getElementById('root'))


src/App.jsx

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

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
export default class App extends Component {
  render() {
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 原生直接使用a标签进行切换 */}
              {/* <a className="list-group-item active" href="./about.html">About</a>
              <a className="list-group-item" href="./home.html">Home</a> */}

              {/* react中靠路由链接进行切换 */}
              {/* 
                有两种Router:
                  <BrowserRouter>
                  <HashRouter>
                  再Router标签中再使用Link进行路由
               */}
                  <Link className="list-group-item" to="/about">About</Link>
                  <Link className="list-group-item" to="/home">Home</Link>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Route path="/about" component={About}/>
                <Route path="/home" component={Home}/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

page/About/index.jsx

import React, { Component } from 'react'

export default class About extends Component {
  render() {
    console.log("接收到参数:", this.props);
    return (
      <div>About ... </div>
    )
  }
}

page/Home/index.jsx

import React, { Component } from 'react'

export default class Home extends Component {
  render() {
    return (
      <div>Home ... </div>
    )
  }
}

components/Header/index.jsx

import React, { Component } from 'react'

export default class index extends Component {
  render() {
    return (
        <div className="row">
            <div className="col-xs-offset-2 col-xs-8">
                <div className="page-header"><h2>React Router Demo</h2></div>
            </div>
        </div>
    )
  }
}

实现选中高亮效果——NavLink

需要借助 <NavLink><NavLink/>实现, <NavLink> 标签配合 activeClassName='类名' 实现,当点击该标签 该样式就会显示。

activeClassName='类名'中的类名默认是active。
eg:
上述案例修改App.jsx

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

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
export default class App extends Component {
  render() {
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                  <NavLink activeClassName='active' className="list-group-item" to="/about">About</NavLink>
                  <NavLink activeClassName='active' className="list-group-item" to="/home">Home</NavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Route path="/about" component={About}/>
                <Route path="/home" component={Home}/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

效果:
在这里插入图片描述
注意:这里我在public文件夹中已经引入了bootstrap.css样式,所以会有样式效果

NavLink的封装

知识点:

  • 组件标签的标签体中的内容会作为children属性传递给组件
  • 在组件中通过children属性就可以指定标签体的内容。

即:
App.jsx

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

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
  render() {
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    {/* 标签体中的内容会作为children属性传递给组件 */}
                  <MyNavLink to="/home">Home</MyNavLink>
                  <MyNavLink to="/about">About</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Route path="/about" component={About}/>
                <Route path="/home" component={Home}/>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

MyNavLink,jsx

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

export default class MyNavLink extends Component {
  render() {
    return (
        <NavLink activeClassName='active' className="list-group-item" {...this.props}/>
    )
  }
}

Switch的使用

一般情况下一个路径(path)只对应一个组件,如果一个路径对应多个组件会是什么效果呢,答案是多个组件都会显示,如:

<div className="col-xs-6">
   <div className="panel">
     <div className="panel-body">
       {/* 注册路由 */}
       <Route path="/about" component={About}/>
       <Route path="/home" component={Home}/>
       <Route path="/home" component={Test}/>
     </div>
   </div>
 </div>

显示如下:
在这里插入图片描述
说明当路径匹配完成之后如果再出现同样的路径就会再次匹配,但是一般情况下一个路径对应一个组件就可以了,所以说为了提升效率,我们希望当匹配到一个路径之后,再碰到该路径就不会进行匹配了。这就可以借助<Switch>组件,用<Switch>组件包裹路由。

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

<div className="col-xs-6">
   <div className="panel">
     <div className="panel-body">
       {/* 注册路由 */}
       <Switch>
         <Route path="/about" component={About}/>
         <Route path="/home" component={Home}/>
         <Route path="/home" component={Test}/>
       </Switch>
     </div>
   </div>
 </div>

补充:样式丢失问题

启动React脚手架,浏览器访问http://localhost:3000/favicon.ico,代表访问public文件夹下的favicon.ico资源。即本地服务器的根路径就是/public文件夹,如果/public文件夹中没有对应的资源就会返回/public/index.html内容。

当路由路径是多级路径,并且刷新页面的时候就会出现样式丢失。因为他会把一级路由放在请求路径进行请求。
eg:
app.jsx

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

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
  render() {
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    {/* 标签体中的内容会作为children属性传递给组件 */}
                  <MyNavLink to="/yang/home">Home</MyNavLink>
                  <MyNavLink to="/yang/about">About</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route path="/yang/about" component={About}/>
                  <Route path="/yang/home" component={Home}/>
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

浏览器:
在这里插入图片描述

解决·:

  • 法一: index.html中引入样式的时候使用相对路径:
<link rel="stylesheet" href="/css/bootstrap.css">
  • 法二: 使用 %PUBLIC_URL%%PUBLIC_URL% 代表的是public文件夹的绝对路径
<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">
  • 法三:使用HashRouter而不是BrowserRouter。
    index.jsx
// 引入react核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入路由组件
import { HashRouter } from 'react-router-dom'
// 引入App组件
import App from './App'

// 渲染App到页面
ReactDOM.render(
    <HashRouter>
        <App/>
    </HashRouter>, document.getElementById('root'))

路由的严格匹配与模糊匹配

模糊匹配

一般情况下:NavLinkto 属性和Routepath属性匹配到的路径是一样的。
NavLinkto 属性是多级路由,但是Routepath只是匹配到第一级路由,那么组件会进行展示;
但是如果当 NavLinkto 属性是一级路由,但是Routepath匹配的是多级路由,组件是不会进行展示的。
这就是模糊匹配。

eg:

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

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
  render() {
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    {/* 标签体中的内容会作为children属性传递给组件 */}
                  <MyNavLink to="/home/a/b">Home</MyNavLink>
                  <MyNavLink to="/about/c/d">About</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route path="/home" component={Home}/>
                  <Route path="/about" component={About}/>
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

组件正常显示:
在这里插入图片描述
但是如果是:

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

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
  render() {
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    {/* 标签体中的内容会作为children属性传递给组件 */}
                  <MyNavLink to="/home">Home</MyNavLink>
                  <MyNavLink to="/about">About</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route path="/home/a/b" component={Home}/>
                  <Route path="/about/c/d" component={About}/>
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

在这里插入图片描述
组件就不展示了。

严格匹配

就是NavLinkto 属性和Routepath属性匹配到的路径必须是一样的。
开启严格匹配的方式:给<Route/> 标签添加 exact 属性。

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

import About from './pages/About'
import Home from './pages/Home'
import Header from "./components/Header"
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
  render() {
    return (
      <div>
        <Header/>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
                    {/* 标签体中的内容会作为children属性传递给组件 */}
                  <MyNavLink to="/home">Home</MyNavLink>
                  <MyNavLink to="/about">About</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route exact={true} path="/home/a/b" component={Home}/>
                  <Route exact={true} path="/about/c/d" component={About}/>
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

严格匹配不要随便开启,可能会导致二级路由无法使用。

Redirect重定向的使用

当Route指明的所有路由都匹配不上的时候,就匹配Redirect中的路由
使用:Redirect在所有Route标签之后使用,利用to属性指明路由地址。

  <div className="col-xs-6">
    <div className="panel">
      <div className="panel-body">
        {/* 注册路由 */}
        <Switch>
          <Route path="/home" component={Home}/>
          <Route path="/about" component={About}/>
          <Redirect to="/about"/>
        </Switch>
      </div>
    </div>
  </div>

嵌套路由

嵌套路由就是在路由组件中再进行路由的导航和注册。
eg:效果:
在这里插入图片描述
新增和改动的页面:
Home/index.jsx

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

import MyNavLink from '../../components/MyNavLink'
import News  from './News'
import Message from './Message'

export default class Home extends Component {
  render() {
    return (
      <div>
        <h3>我是Home组件</h3>
        <div>
          <ul class="nav nav-tabs">
              <li>
                <MyNavLink to="/home/news">News</MyNavLink>
              </li>
              <li>
                <MyNavLink to="/home/message">Message</MyNavLink>
              </li>
          </ul>

          {/* 注册路由 */}
          <Switch>
            <Route path="/home/news" component={News}/>
            <Route path="/home/message" component={Message}/>
            <Redirect to="/home/news"/>
          </Switch>
        </div>
      </div>
    )
  }
}

Home/News/index.jsx

import React, { Component } from 'react'

export default class News extends Component {
  render() {
    return (
     <div>
        <ul>
            <li>news001</li>
            <li>news002</li>
            <li>news003</li>
        </ul>
     </div>
    )
  }
}

Home/Message/index.jsx

import React, { Component } from 'react'

export default class Message extends Component {
  render() {
    return (
    <div>
        <ul>
          <li>
            <a href="/message1">message001</a>&nbsp;&nbsp;
          </li>
          <li>
            <a href="/message2">message002</a>&nbsp;&nbsp;
          </li>
          <li>
            <a href="/message/3">message003</a>&nbsp;&nbsp;
          </li>
        </ul>
      </div>
    )
  }
}

Home/index.js中的 <MyNavLink to="/home/news">News</MyNavLink>匹配的路由就是二级路由,注意这里的路由匹配规则不是直接匹配。所有的路由匹配会按照注册路由的顺序进行匹配, <MyNavLink to="/home/news">News</MyNavLink>会先匹配App.jsx中的注册路由,匹配到了<Route path="/home" component={Home}/>之后再去Home组件匹配注册路由,当匹配到了<Route path="/home/news" component={News}/>就在页面进行显示 。

Home/index.js中的<Redirect to="/home/news"/>, 就是设置当只匹配到了/home, 后面的路径未匹配时在Home页面默认显示的内容。

总结:

  • 注册子路由是需要写上父路由的path值
  • 路由的匹配是按照注册路由的顺序进行的

路由传参

向路由组件传递params参数

使用方法

  • 向路由组件传递params参数 (在路径后面直接接参数)
 <Link to={`/home/message/detail/001/消息1`}>{message.title}</Link>
  • 注册路由时,接收路由组件传递的params参数 (在路径后面使用 :参数名 进行接收)
<Route path="/home/message/detail/:id/:title" component={Detail}/>
  • 在路由组件中接收传递过来的的参数并使用
    路由传递的参数存储在this.props.match.params 中:
render() {
	const {id, title} = this.props.match.params
}

例子

Message/index.jsx

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:'001', title:'消息1'},
    {id:'002', title:'消息2'},
    {id:'003', title:'消息3'}
   ]   
  }
  render() {
    const {messageArr} = this.state
    return (
    <div>
        <ul>
          {
            messageArr.map((message) => {
              return (
                <li key={message.id}>
                  {/* 向路由组件传递params参数 */}
                  <Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link>&nbsp;&nbsp;
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 注册路由 */}
        {/* 接收路由组件传递的params参数 */}
        <Route path="/home/message/detail/:id/:title" component={Detail}/>
      </div>
    )
  }
}

Detail/index.jsx

import React, { Component } from 'react'

export default class Detail extends Component {
  state = {
    dataDetail:[
        {id: '001', context: '我是消息1的内容'},
        {id: '002', context: '我是消息2的内容'},
        {id: '003', context: '我是消息3的内容'},
    ]
  }
  render() {
    const {id, title} = this.props.match.params
    const {dataDetail} = this.state 
    const findDetail = dataDetail.find((detailObj) => {
        return detailObj.id === id
    })
    return (
      <div>
        <div>ID: {id}</div>
        <div>TITLE: {title}</div>
        <div>Context:{findDetail.context}</div>
      </div>
    )
  }
}

在这里插入图片描述

向路由组件传递search参数(query参数)

补充:qs库

  • qs库 可以使用stringify()方法将 对象格式转换为urlencoded编码格式 (key=value&key=value)
    eg:
import qs from 'qs'

let obj = {name:'yang', age:20}
// 转成 urlencoded格式 (key=value&key=value)
console.log(qs.stringify(obj));

输出:

name=yang&age=20
  • qs库 可以使用parse()方法将urlencoded编码格式 转换为对象格式
console.log(qs.parse('name=yang&age=20'))

输出:

{name: 'yang', age: '20'}

使用方式

  • 向路由组件传递search参数 (在路径后面直接接参数)
 <Link to={`/home/message/detail?id=${message.id}&title=${message.title}`}>{message.title}</Link>
  • 注册路由时,无需接收search参数
<Route path="/home/message/detail" component={Detail}/>
  • 在路由组件中接收传递过来的的参数并使用
    路由传递的参数存储在this.props.location.search 中:
    但是还参数是未解析的状态,即urlencoded编码格式,需要借助qs库进行解析
  render() {
	    // 接收search参数
	    const {search}  = this.props.location
	    // slice(1)是为了去掉参数传递时的问号
	    const {id, title} = qs.parse(search.slice(1))
    }

例子

Message/index.jsx

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:'001', title:'消息1'},
    {id:'002', title:'消息2'},
    {id:'003', title:'消息3'}
   ]   
  }
  render() {
    const {messageArr} = this.state
    return (
    <div>
        <ul>
          {
            messageArr.map((message) => {
              return (
                <li key={message.id}>
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link>&nbsp;&nbsp; */}

                  {/* 向路由组件传递search参数 */}
                  <Link to={`/home/message/detail/?id=${message.id}&title=${message.title}`}>{message.title}</Link>&nbsp;&nbsp;
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 注册路由 */}
        {/* 接收路由组件传递的params参数 */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail}/> */}

        {/* search参数无需接受 */}
        <Route path="/home/message/detail" component={Detail}/>
      </div>
    )
  }
}

Detail/index.jsx

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

let obj = {name:'yang', age:20}
// 转成 urlencoded格式 (key=value&key=value)
console.log(qs.stringify(obj));

console.log(qs.parse('name=yang&age=20'))

export default class Detail extends Component {
  state = {
    dataDetail:[
        {id: '001', context: '我是消息1的内容'},
        {id: '002', context: '我是消息2的内容'},
        {id: '003', context: '我是消息3的内容'},
    ]
  }
  render() {
    // 接收params参数
    // const {id, title} = this.props.match.params

    // 接收search参数
    const {search}  = this.props.location
    const {id, title} = qs.parse(search.slice(1))


    const {dataDetail} = this.state 
    const findDetail = dataDetail.find((detailObj) => {
        return detailObj.id === id
    })
    return (
      <div>
        <div>ID: {id}</div>
        <div>TITLE: {title}</div>
        <div>Context:{findDetail.context}</div>
      </div>
    )
  }
}

向路由组件传递state参数

params参数和search参数都会显示在地址栏中,但是state参数就不会显示在地址栏上

使用方式

  • 向路由组件传递state参数 (在路径后面直接接参数)
<Link to={{pathname:'/home/message/detail', state:{id:message.id, title:message.title }}}>{message.title}</Link>
  • 注册路由时,无需接收state参数
<Route path="/home/message/detail" component={Detail}/>
  • 在路由组件中接收传递过来的的参数并使用
    路由传递的参数存储在this.props.location.state 中,是对象格式
  render() {
	     const {id, title} = this.props.location.state 
    }

例子

Message/index.jsx

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:'001', title:'消息1'},
    {id:'002', title:'消息2'},
    {id:'003', title:'消息3'}
   ]   
  }
  render() {
    const {messageArr} = this.state
    return (
    <div>
        <ul>
          {
            messageArr.map((message) => {
              return (
                <li key={message.id}>
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link>&nbsp;&nbsp; */}

                  {/* 向路由组件传递search参数 */}
                  {/* <Link to={`/home/message/detail?id=${message.id}&title=${message.title}`}>{message.title}</Link>&nbsp;&nbsp; */}

                  {/* 向路由传递state参数 */}
                  <Link to={{pathname:'/home/message/detail', state:{id:message.id, title:message.title }}}>{message.title}</Link>&nbsp;&nbsp;
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 注册路由 */}
        {/* 接收路由组件传递的params参数 */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail}/> */}

        {/* search参数无需接受 */}
        {/* <Route path="/home/message/detail" component={Detail}/> */}

        {/* state参数无需接受 */}
        <Route path="/home/message/detail" component={Detail}/>
      </div>
    )
  }
}

Message/Detail/index.jsx

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

let obj = {name:'yang', age:20}
// 转成 urlencoded格式 (key=value&key=value)
console.log(qs.stringify(obj));

console.log(qs.parse('name=yang&age=20'))

export default class Detail extends Component {
  state = {
    dataDetail:[
        {id: '001', context: '我是消息1的内容'},
        {id: '002', context: '我是消息2的内容'},
        {id: '003', context: '我是消息3的内容'},
    ]
  }
  render() {
    // 接收params参数
    // const {id, title} = this.props.match.params

    // 接收search参数
    // const {search}  = this.props.location
    // const {id, title} = qs.parse(search.slice(1))

    // 接收state参数
    const {id, title} = this.props.location.state || {}


    const {dataDetail} = this.state 
    const findDetail = dataDetail.find((detailObj) => {
        return detailObj.id === id
    }) || {}
    return (
      <div>
        <div>ID: {id}</div>
        <div>TITLE: {title}</div>
        <div>Context:{findDetail.context}</div>
      </div>
    )
  }
}

在这里插入图片描述
浏览器地址中没有相关参数信息,但是页面刷新的时候参数不会丢失因为state参数存储在history的location的state中。
state参数是存储在路由组件的history的location的state中的,所以当浏览器的缓存被清空,history就被清空,参数就会丢失,再次访问该地址就无法获取参数就会报错。

路由的两种模式push与replace

浏览器的history会存储我们访问的路径,存储结构是栈结构,存储模式有两种模式push模式和replace模式:

  • push模式:将新访问的路径直接压入栈
  • replace模式:用新访问的路径替换栈顶元素

默认是push模式,可以通过给Link标签添加replace属性即可:

<Link replace={true} to={{pathname:'/home/message/detail', state:{id:message.id, title:message.title }}}>{message.title}</Link>

编程式路由导航

可以不通过Link标签来实现路由导航的路由是编程时路由导航,实际上是操作history身上的API。
注意:只有路由组件才有.props.history属性,才能直接使用如下变成式路由导航
this.props.history的API:

  • replace(跳转路径): replace路由跳转
  • push(跳转路径):push路由跳转
  • go(n):前进或后退|n|步
  • goBack():后退1步
  • goForward():前进1步

replace和push方法可以携带不同的参数(param、query、state)进行路由跳转。
replace跳转

   // replace + params参数
	 this.props.history.replace(`/home/message/detail/${id}/${title}`)
    // replace + query参数
     this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
     // replace + state参数
	 this.props.history.replace(`/home/message/detail`, {id, title})

push跳转

	 // push + params参数
   	this.props.history.push(`/home/message/detail/${id}/${title}`)
    // push + query参数
  	this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
    // push + state参数
    this.props.history.push(`/home/message/detail`, {id, title})

eg:

message/index.jsx

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:'001', title:'消息1'},
    {id:'002', title:'消息2'},
    {id:'003', title:'消息3'}
   ]   
  }
  replaceShow = (id, title)=>{
    // replace + params参数
    // this.props.history.replace(`/home/message/detail/${id}/${title}`)
    // replace + query参数
    // this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
     // replace + state参数
    this.props.history.replace(`/home/message/detail`, {id, title})
  }
  pushShow = (id, title)=>{
    // push + params参数
    // this.props.history.push(`/home/message/detail/${id}/${title}`)
    // push + query参数
    // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
    // push + state参数
    this.props.history.push(`/home/message/detail`, {id, title})
  }
  back = ()=>{
    this.props.history.goBack()
  }
  forward = ()=>{
    this.props.history.goForward()
  }
  go = ()=>{
    this.props.history.go(2)
  }
  render() {
    const {messageArr} = this.state
    return (
    <div>
        <ul>
          {
            messageArr.map((message) => {
              return (
                <li key={message.id}>
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link>&nbsp;&nbsp; */}
                  
                  {/* 向路由组件传递search(query)参数 */}
                  {/* <Link to={`/home/message/detail?id=${message.id}&title=${message.title}`}>{message.title}</Link>&nbsp;&nbsp; */}

                  {/* 向路由传递state参数 */}
                  <Link to={{pathname:'/home/message/detail', state:{id:message.id, title:message.title }}}>{message.title}</Link>&nbsp;&nbsp;

                  <button onClick={()=>this.pushShow(message.id, message.title)}>push查看</button>&nbsp;&nbsp;
                  <button onClick={()=>this.replaceShow(message.id, message.title)} >replace查看</button>
                </li>
              )
            })
          }
        </ul>
        <hr/>
        {/* 注册路由 */}
        {/* 接收路由组件传递的params参数 */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail}/> */}

        {/* search参数无需接受 */}
        {/* <Route path="/home/message/detail" component={Detail}/> */}

        {/* state参数无需接受 */}
        <Route path="/home/message/detail" component={Detail}/>

        <button onClick={this.back}>后退</button>
        <button onClick={this.forward}>前进</button>
        <button onClick={this.go}>前进2</button>

      </div>
    )
  }
}

message/detail/index.jsx
不同的参数接收方式也要做出相应的改变

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

let obj = {name:'yang', age:20}
// 转成 urlencoded格式 (key=value&key=value)
console.log(qs.stringify(obj));

console.log(qs.parse('name=yang&age=20'))

export default class Detail extends Component {
  state = {
    dataDetail:[
        {id: '001', context: '我是消息1的内容'},
        {id: '002', context: '我是消息2的内容'},
        {id: '003', context: '我是消息3的内容'},
    ]
  }
  render() {
    // 接收params参数
    // const {id, title} = this.props.match.params

    // 接收search参数
    // const {search}  = this.props.location
    // const {id, title} = qs.parse(search.slice(1))

    // 接收state参数
    const {id, title} = this.props.location.state || {}


    const {dataDetail} = this.state 
    const findDetail = dataDetail.find((detailObj) => {
        return detailObj.id === id
    }) || {}
    return (
      <div>
        <div>ID: {id}</div>
        <div>TITLE: {title}</div>
        <div>Context:{findDetail.context}</div>
      </div>
    )
  }
}

在这里插入图片描述

withRouter的使用(一般组件实现编程式路由导航)

注意:由于一般组件身上没有.props.history属性,但是如果还是想要实现编程式路由导航可以借助withRouter实现
withRouter可以加工一般组件,让一般组件具备路由组件特有的API(props.history等)
withRouter的返回值是一个带有路由组件API的新组件。
使用:
Header/index.jsx(Header组件是一个一般组件)

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

class Header extends Component {
  back = ()=>{
    this.props.history.goBack()
  }
  forward = ()=>{
    this.props.history.goForward()
  }
  go = ()=>{
    this.props.history.go(2)
  }
  render() {
    return (
        <div className="row">
            <div className="col-xs-offset-2 col-xs-8">
                <div className="page-header">
                  <h2>React Router Demo</h2>
                  <button onClick={this.back}>后退</button>
                  <button onClick={this.forward}>前进</button>
                  <button onClick={this.go}>前进2</button>
                </div>
            </div>
        </div>
    )
  }
}

export default withRouter(Header)
// withRouter可以加工一般组件,让一般组件具备路由组件特有的API(props.history等)

BrowserRouter 和 HashRouter的区别

  1. 底层原理不一样:
    BrowserRouter使用的是H5的history API(注意不是组件实例身上的history),不兼容IE9及以下版本。
    HashRouter使用的是URL的哈希值
  2. url表现形式不一样
    BrowserRouter的路径中没有#,例如: localhost:3000/demo/test
    HashRouter的路径包含#,例如: localhost:3000/#/demo/test
  3. 刷新后对路由state参数的影响
    因为state保存在history对象中,页面刷新并不会关闭浏览器,有记忆功能,所以BrowserRouter没有任何影响
    但是HashRouter刷新后会导致路由state参数的丢失。
  4. 备注: HashRouter可以用于解决一些路径错误相关的问题。HashRouter不会将URL的哈希值(即#后面的值)传给服务器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/47895.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tda4vm mcu1_0应用程序开发系列之ADC采样

文章目录 1. 前言2. 开发过程1. 前言 上一篇我们介绍了如何在tda4vm上拉起MCU域的mcu1_0,感兴趣的小伙伴可以看一下tda4vm如何SPL方式加载MCU域的核?,从本篇开始介绍如何在mcu1_0上开发应用程序,本篇主要介绍mcu1_0上ADC采样应用程序的开发。 2. 开发过程 如果工作中接到…

职业资格证书查询与验证

一、接口介绍 可查询多种类型的职业资格证书&#xff0c;包含&#xff1a;证券从业资格证查询、计算机信息高新技术考试证书查询、计算机技术与软件专业技术资格、全国教师资格证书查询、普通话证书查询合格证明、中小学教师资格考试合格证明&#xff08;NTCE&#xff09;、全国…

隐藏文件夹怎么显示,只需1分钟,快速学会

很多人在工作的过程中&#xff0c;将一些文件给隐藏了起来&#xff0c;后来需要使用的时候&#xff0c;却找不到隐藏的文件夹了。win10如何调出隐藏文件夹&#xff1f;隐藏文件夹怎么显示&#xff1f;只需1分钟&#xff0c;快速学会显示隐藏文件夹&#xff01; 隐藏文件夹怎么显…

【Mysql】复合查询

文章目录**1.基本查询回顾****2.多表查询** (重要)多表查询步骤**3.自连接**4.子查询在from子句中使用子查询5.合并查询1.基本查询回顾 准备工作,创建一个雇员信息表:&#xff08;来自oracle 9i的经典测试表&#xff09; EMP员工表 DEPT部门表 SALGRADE工资等级表 案例1:查询…

SVN+Gitee配置版本控制库

软件 TortoiseSVN&#xff1a;Downloads TortoiseSVN Gitee&#xff1a;https://gitee.com/ 操作步骤 在Gitee中新建仓库&#xff0c;设置仓库名以及模板&#xff08;Readme文件&#xff09;&#xff1b; 启用SVN访问 在仓库的管理页面&#xff0c;选择“功能设置”中的“…

为自己量身打造一个 Rust 项目模板/脚手架

摘要 quick-start-rs(quick start a rust project)是用于快速创建一个 rust 项目的脚手架/模板。 标题&#xff1a;为自己量身打造一个 Rust 项目模板/脚手架深度参考 Rust Code Quick Start文章来自 suhanyujieTags: Rust, utils, quick start, project template&#xff0c;脚…

视频编解码 — 带宽预测

目录 一、带宽预测作用 二、基于延时的带宽预测算法&#xff1a; 1、算法流程 2、计算延时 3、Trendline Filter 4、网络状态判断 5、带宽调整更新 三、基于丢包的带宽预测算法 1、带宽调整 四、最大带宽探测算法 五、最终的预测选择 一、带宽预测作用 控制音视频发…

荧光AF染料477876-64-5,Alexa Fluor 532,AF532 NHS ester

●中文名&#xff1a;AF532 活性酯&#xff0c;AF5 532酯 ●英文名&#xff1a;AF532-NHS &#xff0c;AF532 NHS ester&#xff0c;Alexa Fluor 532 ●外观以及性质&#xff1a; 荧光AF染料是具有磺化基团的荧光物质。AF染料带负电荷&#xff0c;具有亲水性高、亮度高、光稳定…

软件和硬件中的调用

文章目录**1 概述****2.1 程序进程内的调用&#xff1a;函数调用****2.2 程序进程间的调用&#xff1a;IPC****2.3 远程程序调用&#xff1a;RPC****2.4 远程调用REST****3 硬件“调用”****3.1 综述****总线模型****3.2 片内的总线****3.3 Chiplet多DIE封装互联总线****3.4 板…

1.1 统计学习方法的定义与分类

统计学习方法的定义与分类统计学习的概念统计学习的定义统计学习运用到的领域统计学习的步骤统计学习的分类统计学习的概念 统计学习的定义 统计学习 (Statistical Machine Learning) 是关于计算机基于数据构建概率统计模型并运用模型对数据进行预测与分析的一门学科。 以计…

Python任务调度框架Rocketry

文章目录定时任务库对比简介与其余框架的区别安装初试调度器基础测试方法字符串格式具体时间间隔周期某时间段条件 API条件逻辑方法对比执行选项在主进程和线程中执行进程线程异步设置默认选项日志流水线在一个任务后执行输入作为输出会话级参数函数参数TODO&#xff1a;元参数…

为什么说继承是把双刃剑

为什么说继承是把双刃剑 继承其实是把双刃剑&#xff1a;一方面继承是非常强大的&#xff1b;另一方面继承的破坏力也是很强的。 继承广泛应用于各种Java API、框架和类库之中&#xff0c;一方面它们内部大量使用继承&#xff0c;另一方面它们设计了良好的框架结构&#xff0c…

20221130 RabbitMQ

MQ MQ&#xff08;Message Queue&#xff09;消息队列&#xff0c;是基础数据结构中“先进先出”的一种数据结构。一般用来解决应用解耦&#xff0c;异步消息&#xff0c;流量削峰等问题&#xff0c;实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性架构。 主要的…

【正点原子FPGA连载】第二十三章 DDS信号发生器实验摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第二十三章 DDS信…

web网页设计期末课程大作业__公司官网 (曼谷科技 1页)带psd文件

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 家公司官网网站 | 企业官网 | 酒店官网 | 等网站的设计与制 | HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&#xff1a;结构 CSS&…

基于CCE Kubernetes网络与持久化存储实战

✅作者简介&#xff1a; CSDN内容合伙人&#xff0c;全栈领域新星创作者&#xff0c;阿里云专家博主&#xff0c;阿里云问答板块版主&#xff0c;华为云享专家博主&#xff0c;掘金后端评审团成员 &#x1f495;前言&#xff1a; 最近云原生领域热火朝天&#xff0c;那么云原生…

2022年NPDP新版教材知识集锦--【第四章节】(4)

【初始设计与规格阶段】(全部获取文末) 产品设计规格旨在&#xff1a; 明确产品设计并提供量化和客观性; 将产品设计要求传达给设计团队的其他成员; 推进产品从设计到制造的开发。 1、功能性设计(DesignforFunctionality,DFF) 功能设计决定了产品的最终性能&#xff0c;功…

小猴吃苹果-第12届蓝桥杯Scratch选拔赛真题精选

[导读]&#xff1a;超平老师计划推出Scratch蓝桥杯真题解析100讲&#xff0c;这是超平老师解读Scratch蓝桥真题系列的第90讲。 蓝桥杯选拔赛每一届都要举行4~5次&#xff0c;和省赛、国赛相比&#xff0c;题目要简单不少&#xff0c;再加上篇幅有限&#xff0c;因此我精挑细选…

JCTC:基于PWmat中的混合溶剂模型精确计算离子溶解自由能

溶液环境中溶质离子或中间体的自由能计算是电化学研究中最棘手的问题之一。目前单纯的实验手段并不能对发生在溶液中的化学反应过程/机理进行直接探测&#xff0c;许多信息仍主要依赖于理论模拟。对于这一问题&#xff0c;目前很多研究者采用经验势场的溶剂模型方法&#xff0c…

Casein-PEG-Rhodamine B 络蛋白-聚乙二醇-罗丹明B Casein-RB

产品名称&#xff1a;络蛋白-聚乙二醇-罗丹明B 英文名称&#xff1a;Casein-PEG-Rhodamine B 质量控制&#xff1a;95% 原料分散系数PDI&#xff1a;≤1.05 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 用 途&#xff1a;仅供科研实验使用&#xff0c;不用于诊…