当前位置: 首页 > news >正文

06-React的路由

06-React的路由


1.相关理解

1).SPA的理解

  1. 单页Web应用(single page web application,SPA)。
  2. 整个应用只有一个完整的页面。
  3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。
  4. 数据都需要通过ajax请求获取, 并在前端异步展现。

2).路由的理解

a.什么是路由?
  1. 一个路由就是一个映射关系(key:value)
  2. key为路径, value可能是functioncomponent
b.路由分类
①.后端路由:
  1. 理解: valuefunction, 用来处理客户端提交的请求。

  2. 注册路由:

     router.get(path, function(req, res))
    
  3. 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据

②.前端路由:
  1. 浏览器端路由,valuecomponent,用于展示页面内容。

  2. 注册路由:

    <Route path="/test" component={Test}>
    
  3. 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件

3).react-router-dom的理解

  1. react的一个插件库。
  2. 专门用来实现一个SPA应用。
  3. 基于react的项目基本都会用到此库。

2. react基本路由使用

需求:

1).实现:

a.BrowserRouter,Link,Route三个API的基本使用
  1. 完成组件的静态结构,明确好界面中的导航区、展示区

    //App.jsx
    export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转不同的页面 */}<a className="list-group-item active" href="./about.html">About</a><a className="list-group-item" href="./home.html">Home</a> </div></div><div className="col-xs-6"><div className="panel"><div className="panel-body"><About/><Home/></div></div></div></div></div>)}
    }
    
    //Header.jsx
    export default class Header extends Component {render() {return (<div className="page-header"><h2>React Router Demo</h2></div>)}
    }
    
    //About.jsx
    export default class About extends Component {render() {return (<h3>我是About的内容</h3>)}
    }
    
    //Home.jsx
    export default class Home extends Component {render() {return (<h3>我是Home的内容</h3>)}
    }
    
  2. 引入并使用路由API注册路由

    导航区的a标签改为Link标签

    <Link to="/xxxxx">Demo</Link>
    

    展示区写Route标签进行路径的匹配

    <Route path='/xxxx'component={Demo}/>
    
    import { Link, BrowserRouter, Route } from 'react-router-dom'export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* 原生html中,靠<a>跳转不同的页面 */}{/* <a className="list-group-item active" href="./about.html">About</a><a className="list-group-item" href="./home.html">Home</a> */}{/* 在React中靠路由链接实现切换组件--编写路由链接 */}{/* <BrowserRouter> */}<Link className="list-group-item" to="/about">About</Link><Link className="list-group-item" to="/home">Home</Link>{/* </BrowserRouter> */}</div></div><div className="col-xs-6"><div className="panel"><div className="panel-body">{/* 注册路由 */}{/* <BrowserRouter> */}<Route path="/about" component={About} /><Route path="/home" component={Home} />{/* </BrowserRouter> */}</div></div></div></div></div>)}
    }
    

    注意点:

    是两种路由模式中的一种,需要将路由链接和注册路由的标签写在同一个标签中产生关联,为了简化后期编码的便利,一般都是直接用标签将父组件包裹起来,这样整个应用中子组件都可以产生路由关联

    import {BrowserRouter} from 'react-router-dom'
    createRoot(document.getElementById('root')).render(<BrowserRouter><App/></BrowserRouter>)
    
b.路由组件与一般组件

将案例说,Header组件为一般组件,AboutHome组件为路由组件,所以可以将AboutHome组件放在一个名为pages文件夹中,这个文件夹专门用来存放路由组件文件,components文件夹用来存放一般组件的文件

路由组件与一般组件的区别:

1.写法不同:
一般组件:

<Demo/>

​ 路由组件:

<Route path:="/demo"component={Demo}/>

2.存放位置不同:
一般组件:components
路由组件:pages
3.接收到的props不同:
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性:

history:go:f go(n)goBack:f goBack()goForward:f goForward()push:f push(path,state)replace:f replace(path,state)
location:pathname:"/about"search:"state:undefined 
match:params:{}path:"/about"url:"/about"
//About.jsx
export default class About extends Component {render() {console.log('About路由组件:',this.props);return (<h3>我是About的内容</h3>)}
}

c.NavLink与封装NavLink

需求:当点击某个组件链接时,该链接会高亮。

实现:

  1. 原生JS:通过链接元素的点击事件将高亮样式active加到该链接元素上
  2. CSS:通过元素的:hover伪类选择器为元素添加高亮效果
  3. Vue:通过@click事件通过判断条件将高亮样式active加到该链接元素上
  4. React:通过NavLink标签实现,且该标签的默认高亮样式名就为active
<!-- index.html -->
<head><meta charset="UTF-8"><link rel="icon" href="%PUBLIC_URL%/favicon.ico" /><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" href="./css/bootstrap.css"><style>.atguigu{background-color: rgb(209, 137, 4) !important;color: white !important;}</style><title>08</title>
</head>
<body><div id="root"></div>
</body>
</html>
//App.jsx
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group">{/* NavLink可以实现路由链接的高亮通过activeClassName指定样式名 */}<NavLink activeClassName="atguigu" className="list-group-item" to="/about">About</NavLink><NavLink activeClassName="atguigu" 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>)}
}
封装NavLink

可以通过封装NavLink的方式来减少几个NavLink标签实际应用时重复相同的内容

//MyNacLink.jsx
import { NavLink } from 'react-router-dom'
export default class MyNacLink extends Component {render() {const {to,title}=this.prosp  return (<NavLink activeClassName="atguigu" className="list-group-item" to={to}>{title}</NavLink>)}
}
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header/></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/about" title="About"/><MyNacLink to="/home" title="Home"/> </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>)}
}

不足之处在于假如在MyNacLink组件中传递了太多的数值,那么MyNacLink组件取值将会变得繁琐,比如

<MyNacLink to="/about" title="About" a="1" b="2"/>
  1. 通过解构赋值的方式将数值从this.props中取很繁琐:
  2. title值需要另外通过{}
export default class MyNacLink extends Component {render() {const {to,title,a,b}=this.propsreturn (<NavLink activeClassName="atguigu" className="list-group-item" to={to} a={a} b={b}>{title}</NavLink>)}
}

假如将title值写在标签体中,这样就可以通过this.props.children可以获取标签体内容:

//标签体内容是一个特殊的标签属性 
<MyNacLink to="/about" a="1" b="2">About</MyNacLink>
export default class MyNacLink extends Component {render() {console.log(this.props);// const {to,title}=this.propsreturn (<NavLink activeClassName="atguigu" className="list-group-item" to={to}>{title}</NavLink>)}
}

这样就可以通过...运算符将直接将this.props中所有的值都传递到NavLink组件中:

export default class MyNacLink extends Component {render() {return (<NavLink activeClassName="atguigu" className="list-group-item" {...this.props}>{title}</NavLink>)}
}
d.Switch的使用

通常情况下,pathcomponent是一一对应的关系,但是不免有时候会重复path,这样会造成同时显示两个组件的内容:

export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/about" a="1" b="2">About</MyNacLink><MyNacLink to="/home">Home</MyNacLink></div></div><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={Text} /></div></div></div></div></div>)}
}

可以使用Switch来解决这个问题,Switch可以提高路由匹配效率(单一匹配)。

export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/about" a="1" b="2">About</MyNacLink><MyNacLink to="/home">Home</MyNacLink></div></div><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={Text} /></Switch></div></div></div></div></div>)}
}
e.解决多级路径刷新页面样式丢失的问题

假如在路由匹配路径为多重,那么当网页刷新时就会出现样式丢失的问题:

export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/atguigu/about" a="1" b="2">About</MyNacLink><MyNacLink to="/atguigu/home">Home</MyNacLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body"><Switch><Route path="/atguigu/about" component={About} /><Route path="/atguigu/home" component={Home} /></Switch></div></div></div></div></div>)}
}

问题:为什么会造成样式的丢失呢?

回答:在刷新后,请求的bootstrap.css的响应内容发现了变化:

刷新前请求的bootstrap.css的响应内容为一段CSS样式代码:

刷新后请求的bootstrap.css的响应内容为一段HTML代码,而且返回的HTML网页内容就是当前react脚手架项目的index.html文件的内容:

**分析原因:**刷新前后请求bootstrap.css的路径不一样

  • 刷新前的路径:

  • 刷新后的路径:

    可以看到脚手架在请求bootstrap.css资源时,错误的将/atguigu也当成了请求路径的一部分,因此导致请求不到正确的样式资源。

    在脚手架中有一个配置,当脚手架请求不到正确内容时,会将根目录public下的index.html文件返回作为响应

解决方案:

  1. 将引入样式文件的相对路径进行修改

    <link rel="stylesheet" href="/css/bootstrap.css">
    
  2. 在引入样式文件的路径中添加%PUBLIC_URL%

    <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">
    
  3. 将路由模式修改为HashRouter

    import { HashRouter } from "react-router-dom";
    createRoot(document.getElementById('root')).render(<HashRouter><App/></HashRouter>)
    
f.路由的严格匹配与模糊匹配

在路由匹配中有严格匹配与模糊匹配两种模式,默认是模糊模式,因此可以在路由匹配正确路径后面添加其他内容:

export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/about" a="1" b="2">About</MyNacLink><MyNacLink to="/home/a/b">Home</MyNacLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body"><Switch><Route exact path="/about" component={About} /><Route exact path="/home" component={Home} /></Switch></div></div></div></div></div>)}
}

需要注意:模糊匹配只会匹配路径的第一个路径字段,如果第一个匹配不上也不会往后匹配了

export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/about" a="1" b="2">About</MyNacLink><MyNacLink to="/a/home/b">Home</MyNacLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body"><Switch><Route path="/about" component={About} /><Route path="/home" component={Home} /></Switch></div></div></div></div></div>)}
}

开启严格模式:
<Route exact={true}path="/about"component={About}
export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/about" a="1" b="2">About</MyNacLink><MyNacLink to="/home/a/b">Home</MyNacLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body"><Switch><Route exact path="/about" component={About} /><Route exact path="/home" component={Home} /></Switch></div></div></div></div></div>)}
}
  1. 默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
  2. 开启严格匹配:<Route exact={true}path="/about"component={About}/>
  3. 严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
g.Redirect重定向

当需要组件一加载就显示某个路由组件时,可以使用Redirect重定向到指定的路由组件

export default class App extends Component {render() {return (<div><div className="row"><div className="col-xs-offset-2 col-xs-8"><Header /></div></div><div className="row"><div className="col-xs-2 col-xs-offset-2"><div className="list-group"><MyNacLink to="/about">About</MyNacLink><MyNacLink to="/home">Home</MyNacLink></div></div><div className="col-xs-6"><div className="panel"><div className="panel-body"><Switch><Route path="/about" component={About} /><Route path="/home" component={Home} /><Redirect to="/home"/></Switch></div></div></div></div></div>)}
}

3.路由传递参数

1).嵌套路由

需求:

实现:

  1. 注册子路由时要写上父路由的path值
  2. 路由的匹配是按照注册路由的顺序进行的
//Home.js
export default class Home extends Component {render() {return (<div><h2>Home组件内容</h2><div><ul className="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>)}
}

2).向路由组件传递参数

需求:

a.向路由传递params参数
  1. 路由链接(携带参数):

    <Link to='/demo/test/tom/18'}>详情</Link>
    
  2. 注册路由(声明接收):

    <Route path="/demo/test/:name/:age"component={Test}/>
    
    export default class Message extends Component {state = {messageArr: [{ id: '001', title: '消息1' },{ id: '002', title: '消息2' },{ id: '003', title: '消息3' },]}render() {const { messageArr } = this.statereturn (<div><ul>{messageArr.map(msgObj => {return (<li key={msgObj.id}>{/* 向路由组件传递params参数 */}<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;</li>)})}</ul><hr /><Route path="/home/message/detail/:id/:title" component={Detail}/></div>)}
    }
    
  3. 接收参数:

    const{id,title}=this.props.match.params 
    
    const DetailData = [{ id: '001', content: "你好,中国" },{ id: '002', content: "你好,比奇堡" },{ id: "003", content: "你好,海绵宝宝" }
    ]
    export default class Detail extends Component {render() {// 接收params参数console.log(this.props);const { id, title } = this.props.match.paramsconst findResult = DetailData.find((detailObj) => {return detailObj.id === id})return (<ul><li>ID:{id}</li><li>TITLE:{title}</li><li>CONTENT:{findResult.content}</li></ul>)}
    }
    

b.向路由传递search参数
  1. 路由链接(携带参数):

    <Link to='/demo/test?name:=tom&age=18'}>详情</Link>
    
  2. 注册路由(无需声明,正常注册即可):

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

    const{search}=this.props.location
    
  4. 备注:获取到的searchurlencoded编码字符串,需要借助querystring解析

    import qs from "query-string"
    console.log(qs.stringify({name:"tom",age:18}));
    

    urlencoded编码方式:
    let obj={name:"tom",age:18} => name=tom&age=18 key=value&key=value

    const DetailData = [{ id: '001', content: "你好,中国" },{ id: '002', content: "你好,比奇堡" },{ id: "003", content: "你好,海绵宝宝" }
    ]
    export default class Detail extends Component {render() {// 接收search参数console.log(this.props);const {search}=this.props.location//   search.slice(1):去掉字符串前的?const {id,title}=qs.parse(search.slice(1))const findResult = DetailData.find((detailObj) => {return detailObj.id === id})return (<ul><li>ID:{id}</li><li>TITLE:{title}</li><li>CONTENT:{findResult.content}</li></ul>)}
    }
    

c.向路由传递state参数
  1. 路由链接(携带参数):

    <Link to={{path:'/demo/test',state:{name:'tom',age:18})}>详情</Link>
    
  2. 注册路由(无需声明,正常注册即可):

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

    const DetailData = [{ id: '001', content: "你好,中国" },{ id: '002', content: "你好,比奇堡" },{ id: "003", content: "你好,海绵宝宝" }
    ]
    export default class Detail extends Component {render() {// 接收state参数// 切记需要添加 ||{} 以免引起报错   const {id,title}=this.props.location.state||{}const findResult = DetailData.find((detailObj) => {return detailObj.id === id})||{}return (<ul><li>ID:{id}</li><li>TITLE:{title}</li><li>CONTENT:{findResult.content}</li></ul>)}
    }
    
  4. 备注:刷新也可以保留住参数

3).push模式和replace模式

  1. push模式相当于history模式,是在浏览器上一条浏览记录添加覆盖一条新的浏览记录
  2. replace模式相当于hash模式,是将浏览器上一条替换成新的浏览记录

在注册路由时开启replace模式:

<Route replace={true} path="/home/message/detail" component={Detail}/>

4.编程式路由导航

当需要在事件中进行跳转路由时,就可以使用编程式路由。

我们知道在路由组件的props中包含有historylocationmatch,其中history中的gogoBackgoForwardpushreplace三个方法就可以供我们实现编程式路由导航

a.基本使用
export default class Message extends Component {state = {messageArr: [{ id: '001', title: '消息1' },{ id: '002', title: '消息2' },{ id: '003', title: '消息3' },]}replaceShow = (id, title) => {this.props.history.replace(`/home/message/detail`)}pushShow = () => {this.props.history.push(`/home/message/detail`)}back=()=>{this.props.history.goBack()}forward=()=>{this.props.history.goForward()}render() {console.log(this.props);const { messageArr } = this.statereturn (<div><ul>{messageArr.map(msgObj => {return (<li key={msgObj.id}><Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>&nbsp;<button onClick={() => this.pushShow()}>push查看</button>&nbsp;<button onClick={() => this.replaceShow()}>replace查看</button></li>)})}</ul><hr /><Route path="/home/message/detail" component={Detail} /><button onClick={this.back}>回退</button><button onClick={this.forward}>前进</button></div>)}
}

b.路由跳转+传递参数
①.传递param参数
export default class Message extends Component {state = {messageArr: [{ id: '001', title: '消息1' },{ id: '002', title: '消息2' },{ id: '003', title: '消息3' },]}replaceShow = (id, title) => {// replace跳转+传递param参数this.props.history.replace(`/home/message/detail/${id}/${title}`)}pushShow = (id, title) => {// push跳转+传递param参数this.props.history.push(`/home/message/detail/${id}/${title}`)}back=()=>{this.props.history.goBack()}forward=()=>{this.props.history.goForward()}render() {console.log(this.props);const { messageArr } = this.statereturn (<div><ul>{messageArr.map(msgObj => {return (<li key={msgObj.id}>{/* 向路由组件传递params参数 */}{<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;&nbsp;<button onClick={()=>this.pushShow(msgObj.id,msgObj.title)}>push查看</button>&nbsp;<button onClick={()=>this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button> </li>)})}</ul><hr /><Route path="/home/message/detail/:id/:title" component={Detail}/> <button onClick={this.back}>回退</button><button onClick={this.forward}>前进</button></div>)}
}
②.传递query参数
export default class Message extends Component {state = {messageArr: [{ id: '001', title: '消息1' },{ id: '002', title: '消息2' },{ id: '003', title: '消息3' },]}replaceShow = (id, title) => {// replace跳转+传递query参数this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)}pushShow = (id, title) => {// push跳转+传递query参数this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)}back=()=>{this.props.history.goBack()}forward=()=>{this.props.history.goForward()}render() {console.log(this.props);const { messageArr } = this.statereturn (<div><ul>{messageArr.map(msgObj => {return (<li key={msgObj.id}>{/* 向路由组件传递search参数 */}<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;&nbsp;<button onClick={()=>this.pushShow(msgObj.id,msgObj.title)}>push查看</button>&nbsp;<button onClick={()=>this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button> </li>)})}</ul><hr /><Route path="/home/message/detail" component={Detail}/> <button onClick={this.back}>回退</button><button onClick={this.forward}>前进</button></div>)}
}
③.传递state参数
export default class Message extends Component {state = {messageArr: [{ id: '001', title: '消息1' },{ id: '002', title: '消息2' },{ id: '003', title: '消息3' },]}replaceShow = (id, title) => {// replace跳转+传递state参数this.props.history.replace(`/home/message/detail`, { id, title })}pushShow = (id, title) => {// push跳转+传递state参数this.props.history.push(`/home/message/detail`, { id, title })}back=()=>{this.props.history.goBack()}forward=()=>{this.props.history.goForward()}render() {console.log(this.props);const { messageArr } = this.statereturn (<div><ul>{messageArr.map(msgObj => {return (<li key={msgObj.id}>{/* 向路由组件传递state参数 */}<Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>&nbsp;<button onClick={() => this.pushShow(msgObj.id, msgObj.title)}>push查看</button>&nbsp;<button onClick={() => this.replaceShow(msgObj.id, msgObj.title)}>replace查看</button></li>)})}</ul><hr /><Route path="/home/message/detail" component={Detail} /><button onClick={this.back}>回退</button><button onClick={this.forward}>前进</button></div>)}
}
c.withRouter

如果需要使一般路由也有跟路由组件一样的props属性以此来实现一些效果,比如浏览记录的回退和前进,可以使用withRouter让一般组件具备路由组件所特有的API

//Header.jsx
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()}render() {return (<div className="page-header"><h2>React Router Demo</h2>&nbsp;<button onClick={this.back}>后退</button>&nbsp;<button onClick={this.forward}>前进</button></div>)}
}
export default withRouter(Header)
  1. withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
  2. withRouter的返回值是一个新组件

5.BrowserRouter与HashRouter的区别

  1. 底层原理不一样:
    • BrowserRouter使用的是H5的nistory API,不兼容IE9及以下版本。
    • HashRouter使用的是URL的哈希值。
  2. url表现形式不一样
    • BrowserRouter的路径中没有#,例如:loca1host:3009/demo/test
    • HashRouter的路径包含#,例如:localhost:3o00/#/demo/test
  3. 刷新后对路由state参数的影响
    • BrowserRouter没有任何影响,因为state保存在history对象中。
    • HashRouter刷新后会导致路由state参数的丢失。
  4. 备注:HashRouter可以用于解决一些路径错误相关的问题。

相关文章:

06-React的路由

06-React的路由 1.相关理解 1).SPA的理解 单页Web应用&#xff08;single page web application&#xff0c;SPA&#xff09;。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过ajax请求获取, 并在前端异步展现。…...

虹科方案 | 加州理工学院利用HK-TrueNAS开展地震研究

一、客户背景 加州理工学院(CalTech)是世界顶尖的理工类科学研究型学府之一。加州理工学院地震实验室是加州理工学院地质与行星科学部(GPS)的一个分支机构&#xff0c;成立于1921年&#xff0c;自20年代以来一直是世界地震学研究中心&#xff0c;并且几十年来一直是媒体对大地…...

宝塔面板部署express以及MySql项目

第一次在宝塔面板上部署express和MySql项目&#xff0c;部署过程一直跑不通接口&#xff0c;特此记录一下。 在部署的时候&#xff0c;建议第一步把数据库MySql给跑通&#xff0c;中间好多原因是由于数据库的原因给引起的。 一.连接数据库 &#xff08;1&#xff09;在宝塔面…...

联盟链学习笔记-网络的创建

联盟链学习笔记 初始网络 下图是初始网络网络N的参考图 排序服务 在定义 网络 N 的时候&#xff0c;第一件事情就是定义一个 排序服务O4。O4 最初被配置并且由组织 R4 的一个管理员来启动&#xff0c;并且由 R4 管理。配置 NC4 包含了描述网络管理能力初始集合的规则。最初在…...

System.Drawing.Common.Bitmap跨平台的替代方案

使用SkiaSharp SkiaSharp是Skia Graphics Library的.Net跨平台实现&#xff0c;它可以在Windows&#xff0c;macOS&#xff0c;Linux&#xff0c;iOS&#xff0c;Android和其他平台上使用。 例如需要Linux版&#xff0c;则安装第一个和第四个&#xff1a; 以下是使用SkiaShar…...

深入理解 Java 泛型

没有泛型是怎样的 了解点 Java 历史的都知道,泛型是从 JDK 1.5 版本添加的特性,在 JDK1.5 之前,Java 很多特性都是没有的例如:泛型、注解、自动装箱和拆箱、可变参数。在介绍泛型之前,我们先来看看,如果没有泛型的世界是怎么样的。 假设有一个 List,我只想把 String 类…...

【基础篇】七、Flink核心概念

文章目录 1、并行度2、并行度的设置3、算子链4、禁用算子链5、任务槽6、任务槽和并行度的关系 1、并行度 要处理的数据量很多时&#xff0c;可以把一个算子的操作&#xff08;比如前面demo里的flatMap、sum&#xff09;&#xff0c;"复制"多份到多个节点&#xff0c…...

06-Scala面向对象

面向对象编程 ​ Scala是一门完全面向对象的语言&#xff0c;摒弃了Java中很多不是面向对象的语法。 ​ 虽然如此&#xff0c;但其面向对象思想和 Java的面向对象思想还是一致的 Scala包 1&#xff09;基本语法 Scala中基本的package包语法和 Java 完全一致 例如&#xf…...

【设计模式】单例模式、“多例模式”的实现以及对单例的一些思考

文章目录 1.概述2.单例模式实现代码2.1.饿汉式单例2.2.懒汉式单例2.3.双检锁单例2.4.静态内部类单例2.5.枚举单例 3.对单例的一些思考3.1.是否需要严格的禁止单例被破坏&#xff1f;3.2.懒汉式真的比饿汉式更佳吗&#xff1f;3.3.单例存在的问题 4.其他作用范围的单例模式4.1.线…...

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目

idea 2022 一个工作空间下导入git项目 后 无法导入第二个git项目 如图所示 我导入了一个git项目后&#xff0c;菜单栏出现了一个git按钮 找不到 导入git项目的按钮了 方式1、 通过idea设置 打开全局设置 如下图 把git先改为none&#xff0c;保存 保存后就可以看到 VCS按钮 导入…...

泛在电力物联网的关键技术与未来发展策略-安科瑞黄安南

摘要: 文章分析了泛在电力物联网的内涵及其主要特征&#xff0c;针对泛在电力物联网的建设目标、基本构架以及关键技术与未来发展策略进行综合探讨&#xff0c;期待得到专业人士的指点。 关键词: 泛在电力物联网&#xff0c; 网络规划&#xff0c; 网络发展 随着能源革命的不…...

iWall:支持自定义的Mac动态壁纸软件

iWall Mac是一款动态壁纸软件&#xff0c;它可以使用任何格式的漂亮视频&#xff08;无须转换&#xff09;、图片、动画、Flash、gif、swf、程序、网页、网站做为您的动态壁纸、动态桌面&#xff0c;并且可以进行交互。 这款软件功能多、使用简单、体积小巧、不占用资源、运行…...

【Docker 内核详解】namespace 资源隔离(四):Mount namespace Network namespace

【Docker 内核详解 - namespace 资源隔离】系列包含&#xff1a; namespace 资源隔离&#xff08;一&#xff09;&#xff1a;进行 namespace API 操作的 4 种方式namespace 资源隔离&#xff08;二&#xff09;&#xff1a;UTS namespace & IPC namespacenamespace 资源隔…...

STM32简介

STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器&#xff0c;常应用在嵌入式领域如&#xff1a; 智能车&#xff08;用stm32做寻迹小车&#xff0c;读取光电传感器或者摄像头数据&#xff0c;然后驱动电机前进和转弯&#xff09;&#xff1b; 无人机&#xff08;用stm3…...

Yum安装JDK11

一、安装命令 &#xff1a; yum install java-11-openjdk二、执行以下命令来查看 JDK 11 的安装信息&#xff1a; yum list installed | grep java-11-openjdk三、找到 JDK 11 的软件包名称&#xff08;使用以下命令来查询软件包的安装位置&#xff09;&#xff1a; rpm -ql…...

[HNCTF 2022 WEEK2]ez_ssrf题目解析

这题主要是引入ssrf这个漏洞攻击&#xff0c;本质上没有更深入的考察 本题是需要我们去伪造一个ssrf的请求头去绕过 题目开始给了我们信息让我们去访问index.php fsockopen函数触发ssrf fsockopen() 函数建立与指定主机和端口的 socket 连接。然后&#xff0c;它将传入的 bas…...

OpenFOAM: twoPhaseEulerFoam解读

twoPhaseEulerFoam全解读之一(转载) 本系列将对OpenFOAM-2.1.1 中的 twoPhaseEulerFoam 求解器进行完全解读&#xff0c;共分三部分&#xff1a;方程推导&#xff0c;代码解读&#xff0c;补充说明。本篇进行方程推导&#xff0c;详细介绍如果从双流体模型出发得到 twoPhaseEu…...

ffmpeg跨平台arm编译-ubuntu

目录 1. 安装必要的编译器2. 安装必要的依赖项3. 配置编译选项4. 编译安装 1. 安装必要的编译器 32位系统&#xff1a; sudo apt-get update sudo apt-get install gcc-arm-linux-gnueabihf sudo apt-get install g-arm-linux-gnueabihf64位系统&#xff1a; sudo apt-get u…...

Vue 网络处理 - axios 异步请求的使用,请求响应拦截器

目录 一、axiox 1.1、axios 简介 1.2、axios 基本使用 1.2.1、下载核心 js 文件. 1.2.2、发送 GET 异步请求 1.2.3、发送 POST 异步请求 1.2.4、发送 GET、POST 请求最佳实践 1.3、请求响应拦截器 1.3.1、拦截器解释 1.3.2、请求拦截器的使用 1.3.3、响应拦截器的使用…...

单目3D目标检测——MonoDLE 模型训练 | 模型推理

本文分享 MonoDLE 的模型训练、模型推理、可视化3D检测结果。 模型原理&#xff0c;参考我这篇博客&#xff1a;【论文解读】单目3D目标检测 MonoDLE&#xff08;CVPR2021&#xff09;_一颗小树x的博客-CSDN博客 源码地址&#xff1a;https://github.com/xinzhuma/monodle 目…...

CSS悬停卡片翻转明信片效果源码附注释

运行效果演示: HTML页面代码: <!DOCTYPE html> <html lang="en" > <head>...

使用kaliber与imu_utils进行IMU、相机+IMU联合标定

目录 1 标定工具编译 1.1 IMU标定工具 imu_utils 1.2 相机标定工具 kaliber 2 标定数据录制 3 开始标定 3.1 IMU标定 3.2 相机标定 3.3 相机IMU联合标定 4 将参数填入ORBSLAM的文件中 1 标定工具编译 1.1 IMU标定工具 imu_utils 标定IMU我们使用imu_utils软件进行标定…...

统一观测丨使用 Prometheus 监控 SQL Server 最佳实践

作者&#xff1a;啃唯 SQL Server 简介 SQL Server 是什么&#xff1f; Microsoft SQL Server 是 Microsoft 推出的关系型数据库解决方案&#xff0c;支持企业 IT 环境中的各种事务处理、商业智能和分析应用程序。Microsoft SQL Server 是市场领先的数据库技术之一。 SQL S…...

最短无序连续子数组

题目链接 最短无序连续子数组 题目描述 注意点 找出符合题意的 最短 子数组&#xff0c;并输出它的长度-100000 < nums[i] < 100000 解答思路 本题的数组可以分为三段&#xff0c;左段中段和右段&#xff0c;如下图所示 观察规律可知&#xff0c;左段元素始终比中段…...

更新 | 持续开源迅为RK3568驱动指南第十二篇-GPIO子系统

《iTOP-RK3568开发板驱动开发指南》更新&#xff0c;本次更新内容对应的是驱动&#xff08;第十二期_GPIO子系统-全新升级&#xff09;视频&#xff0c;后续资料会不断更新&#xff0c;不断完善&#xff0c;帮助用户快速入门&#xff0c;大大提升研发速度。 文档教程更新至第十…...

centos7安装erlang23.3.4.11及rabbitmq3.9.16版本

rpm包有系统版本要求&#xff0c;el是Red Hat Enterprise Linux(EL)的缩写。 EL7是Red Hat 7.x&#xff0c;Centos 7.x EL8是Red Hat 8.x, Centos 8.x 所以我们在安装erlang及rabbitmq时需要选择与自己的服务器相对应的rpm包 # rabbitmq的rpm安装包 https://github.com/rabbi…...

VMware和Debian下载

文章目录 ⭐️写在前面的话⭐️一、VMware二、Debain三、建立虚拟机&#x1f680; 先看后赞&#xff0c;养成习惯&#xff01;&#x1f680;&#x1f680; 先看后赞&#xff0c;养成习惯&#xff01;&#x1f680; ⭐️写在前面的话⭐️ CSDN主页&#xff1a;程序员好冰 目前在…...

mysql面试题48:MySQL中 Innodb的事务与日志的实现方式

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官: Innodb的事务与日志的实现方式 以下是InnoDB事务和日志的实现方式的详细说明: 事务日志(Transaction Log): InnoDB使用事务日志来保证事务的…...

数据结构 优先级队列(堆)

数据结构 优先级队列(堆) 文章目录 数据结构 优先级队列(堆)1. 优先级队列1.1 概念 2. 优先级队列的模拟实现2.1 堆的概念2.2 堆的存储方式2.3 堆的创建2.3.1 堆向下调整2.3.2 堆的创建2.3.3 建堆的时间复杂度 2.4 堆的插入与删除2.4.1 堆的插入2.4.2 堆的删除 2.5 用堆模拟实现…...

如何在edge浏览器中给PDF添加文字批注

我用的edge浏览器是目前最新版的&#xff08;一般自动更新到最新版&#xff09; 最近&#xff0c;我喜欢用edge浏览器查看PDF&#xff0c;节省电脑资源&#xff0c;快捷且方便。 但edge对PDF的标注种类较少&#xff0c;主要是划线和涂色&#xff0c;文字批注功能尚未出现在工具…...

长沙网站建设 个人/建立一个国外的网站

这篇文章主要介绍了在telnet下操作memcache详解,telnet下的memcache操作命令详解,需要的朋友可以参考下 在定位问题、测试等时候经常需要对memcache的数据进行一些操作&#xff0c;但是其本身没有自带的客户端&#xff0c;所以只能通过telnet来进行操作。 通过telnet连接memcac…...

公司网站要使用我个人的信息备案/网站做外链平台有哪些

CVSS&#xff0c;全称Common Vulnerability Scoring System&#xff0c;即“通用漏洞评分系统”&#xff0c;是一个“行业公开标准&#xff0c;其被设计用来评测漏洞的严重程度&#xff0c;并帮助确定所需反应的紧急度和重要度” 。CVSS是安全内容自动化协议&#xff08;SCAP&…...

浏览器兼容测试网站/外贸推广网站

什么是A-GPS?所谓A-GPS(AssistedGPS)是一种结合网络基站信息和GPS信息对移动台进行定位的技术&#xff0c;暨利用全球卫星定位系统GPS&#xff0c;又利用移动基站&#xff0c;解决了GPS覆盖的问题&#xff0c;可以在GSM/GPRS、WCDMA和CDMA2000网络中使用。由于借用网络数据定位…...

wordpress美容养生/长沙网站定制

const int LOG 20;//根据点数来取&#xff0c;取LOG >logn就行了 20已经可以处理1e6以下的数据了int par[N][LOG],dep[N];void dfs(int u,int fa,int depth){dep[u]depth;if(u1){ //对于根来说&#xff0c;往上跳无论几下都是他自己。我习惯把1定为根所以写 u 1for(int …...

商城网站制作的教程/国家卫生健康委

《计算机控制4.Z变换.ppt》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《计算机控制4.Z变换.ppt(30页珍藏版)》请在人人文库网上搜索。1、1,第4部分 Z变换,Z变换的定义,4.1,Z变换的求法,4.2,Z反变换,4.3,线性离散系统的Z变换分析,4,2,Z变换,Z变换的定义,4.1,Z变换的…...

东胜做网站/泰州seo网络公司

prime算法里有一个求最短路径的MidEdge函数&#xff0c;我自己写的函数输出的全为0&#xff0c;不知道为什么templatevoid MGraph::Prim(MGraph G){for (int i 1; i < G.vertexNum; i){lowcost[i] G.arc[0][i];//初始化adjvex[i] 0;//最小生成树的顶点集合}lowcost[0] 0…...