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可以用于解决一些路径错误相关的问题。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在pycharm中运行js文件,附加node.js下载步骤

文章目录 一、前言二、node.js安装和配置(如果之前就安装好了可以直接跳过)1、进入官网下载安装包2、在本地安装node.js3、环境配置4、验证是否安装成功5、修改下载位置(默认是在c盘&#xff0c;这个根据个人需求)6、设置默认模块包7、测试一下是否修改成功(要进入管理员模式的…

Qt 布局(QSplitter 类QDockWidget 类) 总结

一、QSplitter 类(窗口分割) QSplitter类是一个Qt框架提供的基础窗口控件类&#xff0c;用于分割窗口&#xff0c;使得用户可以通过拖动分隔条来调节子窗口的大小。QSplitter在用户界面设计中非常常见&#xff0c;经常用于划分窗口区域&#xff0c;使得程序可以同时显示多个子…

【算法|动态规划No.20】leetcode416. 分割等和子集

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

软件开源快速开发框架:降本增效,助力流程化办公!

随着时代的进步和社会的发展&#xff0c;应用软件开源快速开发框架的优势特点&#xff0c;可以让不少客户朋友顺利实现流程化办公&#xff0c;朝着数字化方向迈进。流辰信息是专业研发低代码技术平台的服务商&#xff0c;一直在低代码平台领域深耕细作&#xff0c;努力钻研&…

海思平台SS528V100编译 linux kernel tun.c eth_get_headlen 编译 出错的问题

osdrv目录下 make kernel 会去opensource目录下解压linux内核压缩包 同时打上很多补丁 如上图 查看Makefile 如下 有打补丁的命令 然后 然后我们的应用程序用到一个特性 需要打开tun/tab这两个属性 打开之后编译内核出错 查到最后发现 没打补丁之前的文件 没问题 …

论文阅读:Offboard 3D Object Detection from Point Cloud Sequences

目录 概要 Motivation 整体架构流程 技术细节 3D Auto Labeling Pipeline The static object auto labeling model The dynamic object auto labeling model 小结 论文地址&#xff1a;[2103.05073] Offboard 3D Object Detection from Point Cloud Sequences (arxiv.o…

Springboot-MyBatisPlue入门

一 创建项目&#xff0c;选择spring boot 初始化&#xff0c;配置相关信息 第五步创建实体类 二 快速开发实体类的jar包--lombok <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12<…

OpenCV完美实现两张图片的全景拼接(详细教程)

目录 1&#xff0c;主要步骤 1.1 导入需要的包和模块&#xff0c;并读取两张待拼接的图片&#xff0c;这里我们假设它们为 left.jpg 和 right.jpg。 1.2 创建SIFT检测器 1.3 创建一个基于 FLANN 的匹配器 1.4 筛选过程删除掉一些不合适的匹配点&#xff0c;只保留最好的…

Hadoop3教程(十二):MapReduce中Shuffle机制的概述

文章目录 &#xff08;95&#xff09; Shuffle机制什么是shuffle&#xff1f;Map阶段Reduce阶段 参考文献 &#xff08;95&#xff09; Shuffle机制 面试的重点 什么是shuffle&#xff1f; Map方法之后&#xff0c;Reduce方法之前的这段数据处理过程&#xff0c;就叫做shuff…

利用ChatGPT练习口语

目录 ChatGPT 这两天发布了一个激动人心的新功能&#xff0c;App端&#xff08;包括iOS和Android&#xff09;开始支持语音对话以及图片识别功能。 这两个功能一如既往的优先开放给Plus用户使用&#xff0c;现在将App更新到最新版本&#xff0c;就能体验。 为什么说激动人心&a…

解决 vscode使用Prettier格式化js文件报错:Cannot find module ‘./parser-babylon‘

报错如下&#xff1a; ["ERROR" - 11:48:58] Error formatting document. ["ERROR" - 11:48:58] Cannot find module ./parser-babylon Require stack: - d:\VueCode\VueProject\myqqmusic\node_modules\prettier\index.js - c:\Users\Administrator.SKY-2…

ROS键盘遥控机器人,通过参数服务器指定速度

1、引言 在上节的驱动机器人&#xff0c;我们知道是cmd_vel话题发布一串Twist类型消息来控制&#xff0c;我们可以输入如下命令查看这个Twist的详细信息&#xff1a;rosmsg show geometry_msgs/Twist geometry_msgs/Vector3 linear float64 x float64 y float64 z geome…

1-图像读取

skimage import skimage from skimage import io, color# 读取灰度图&#xff0c;能做到16bit无损 img io.imread(CT-220s_681.tif) # 直接就是numpy类型&#xff0c;dtype根据图片格式决定,np默认float64格式 print(img.shape, type(img), img.dtype) print(img)# 读取彩色…

IDEA spring-boot项目启动,无法加载或找到启动类问题解决

问题描述&#xff1a;找不到或无法加载主类 xxx.xxx.xxx.Classname 解决方案&#xff1a; 1.检查启动设置&#xff1a; 启动类所在包运行环境&#xff08;一般选择默认即可&#xff09;设置完成即可进行运行测试 2.如果第一步没有解决问题&#xff0c;试着第二步&#xff1a…

广州华锐互动:炼钢工厂VR仿真实训系统

随着科技的发展&#xff0c;我们的教育体系和职业培训方法也在迅速变化。其中&#xff0c;虚拟现实&#xff08;VR&#xff09;技术的出现为我们提供了一种全新的学习和培训方式。特别是在需要高度专业技能和安全性的领域&#xff0c;如钢铁冶炼。本文将探讨如何使用VR进行钢铁…

机器人控制算法——两轮差速驱动运动模型

1.Introduction 本文主要介绍针对于两轮差速模型的逆运动学数学推导。因为在机器人控制领域&#xff0c;决策规划控制层给执行器输出的控制指令v(车辆前进速度)和w(角速度)&#xff0c;因此&#xff0c;我们比较关心&#xff0c;当底层两个驱动电机接收到此信息&#xff0c;如何…

Rust 基础

文章目录 一、变量1.1 不可变变量/可变变量/常量1.2 变量的可覆盖性 二、数据类型2.1 数据类型 & 编译器自动推导机制2.2 标量与复合 三、函数3.1 普通函数3.2 匿名函数/闭包3.3 函数指针3.4 高阶函数3.5 函数部分完整代码&#xff1a; 一、变量 1.1 不可变变量/可变变量/…

自定义安装Redhat8.6镜像:

目录 一、创建虚拟机 二、选择需要安装的镜像 三、选择正确的操作系统和版本 四、更改虚拟机名称和位置 五、配置处理器和内核数量以及内存 配置规则&#xff1a; 六、网络类型、I/O控制类型、磁盘类型使用推荐 即可 网络类型&#xff1a; I/O控制类型: 磁盘类型: 七…

报道 | 2023-2024年1月国际运筹优化会议汇总

2023年10月、11月、12月召开会议汇总&#xff1a; 2023 International Conference on Optimization and Applications (ICOA) Location: Abu Dhabi, United Arab Emirates Important dates: Conference: October 05-06, 2023 Details: https://lct.ac.ae/en/icoa/ 2023 INF…

21GA-ELM,遗传算法优化ELM预测,并和优化前后以及真实数值进行对比,确定结果,基于MATLAB平台,程序已经调通,可以直接运行,需要直接拍下。

GA-ELM&#xff0c;遗传算法优化ELM预测&#xff0c;并和优化前后以及真实数值进行对比&#xff0c;确定结果&#xff0c;基于MATLAB平台&#xff0c;程序已经调通&#xff0c;可以直接运行&#xff0c;需要直接拍下。 21matlab时间序列预测极限学习遗传优化算 (xiaohongshu.co…