React-Router复习——B站

路由

启用路由三步骤:

  • 在网站的App根节点上包裹一个<HashRouter>
  • 在导航栏使用<Link>标签包裹跳转组件
  • 在显示区域中使用<Route>标签包裹需要跳转到的组件页面

注意:Router标签内只能有一个根元素

1 路由安装和使用

  1. 安装依赖
npm install react-router-dom --save
  1. 引入对象
import {BrowserRouter as Router, Route, Link} from "react-router-dom";

Route组件:负责存放响应地址和响应组件
Link组件:负责触发响应
Router组件:负责存放所有的响应体,即Route组件必须在Router种

  1. 使用
    其中Home和A为React自定义组件
<Router>
	<div>
		<Link to="/">Home</Link>
		...
		<Route exact path="/" component={Home} />
		<Route path="/a" component={A} />
		...
	</div>
</Router>

注意:exact路由严格匹配,如果没有该参数,则该路由会匹配所有以/开头的路由,那Home组件每次都会被挂载(遵循一个原则,目标路由会匹配所有子路由

注意:假如有一个 Link 标签,点击后跳转到 /abc/def
BrowserRouter: http://localhost:8080/abc/def
HashRouter: http://localhost:8080/#/abc/def
如果有服务端的动态支持,建议用BrowserRouter

2 路由配置

路由信息都保存在props中

  • props.match.url:当前路由地址
  • props.match.path:通常与url一致,只是在遇到:myParam传参时:
path:"/demo/page2/:myParam" 
url:"/demo/page2/小红" 
  • props.match.isExact:标识是否全匹配,boolean
  • props.location.search:获取url显式参数 ,如?abc=1
  • props.match.params:获取url的冒号参数,如:路由:/a/b/:myParam 匹配到 /a/b/c则获取到c

注意:路由信息不是实时更新 !

实时更新解释:
假如我通过点击 标签,让路由从 /a 跳转到 /b ,也就是说,从显示 A 组件到显示 B 组件。会发生以下事情:
【1】如果 Link 标签里有一个 onClick 事件,那么显然可以拿到 location 属性的值。
在该事件执行的这段时间,props.location 的值,是 url 更新之前的。
并且,window.location(也就是原生的),其 url 也是更新之前的;
【2】那什么时候可以获取到更新之后的 url 呢?
答案是路由更新后,所对应的那个组件,在挂载的时候,生命周期处于 componentWillMount 时,可以获取到最新的 url。
因此如果需要第一时间在父组件内拿到更新后的值,那么需要在父组件,将回调函数传给子组件才可以实现。
————————————————
版权声明:本文为CSDN博主「qq20004604」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq20004604/article/details/79440409

2.1 路由传参

2.1.1 url-冒号传值 (动态路由)(:param)

两个步骤:配置Link和Route

此时value中包括两个属性:url和title
<Link to={`/a/${value.url}`}>{value.title}</Link>
<Route path="/a/:p1" component={A}/>

上述代码,Link跳转了一个路由,而Route定义了一个动态路由,该路由匹配前缀为/a/的url,后面接受一个:p1参数
路由的传值存放在:this.props.match.params.参数名中,在挂载的组件中可以进行获取

componentDidMount(){
	console.log(this.props.match.params.p1)
}

2.1.2 url-get传值(?param=)

使用get传值,Route不变,Link变化

<Link to={"/a?p1="+value.url}>{value.title}</Link>
<Route path="/a" component={A}/>

在挂载的相应对象中获取传值:this.props.location.search

componentDidMount(){
	console.log(this.props.location.search)
}

此时search中的值为:?p1=123,可以考虑使用第三方模块来解析:npm install url --save
此时传递值可以很方便的解析成对象{key:value},注意url.parse第二个参数传递为true才会解析!

console.log(
url.parse(
	this.props.location.search,true
).query)

2.1.3 Link-属性传值(to={obj})

to={obj},其中obj为一个对象,包括两个属性:pathnamestate(state可以自定义名字),注意刷新后无法获取传递过来的值
获取传递过来的值:this.props.location.state

2.1.4 JS函数跳转传值

this.props.history.push(obj)来跳转路由,并传递参数。其中obj同第二条内容一样,获取方式同上:this.props.location.state

2.1.5 参数传递示例

//to传参 
<Link to={{pathname:this.props.match.url+'/page1',pp:{name:'pp',age:11}}}>page1</Link> 

//:myParam传参 
<Link to={'/demo/page2/'+{item}}><Link> 

//?传参 
<Link to={'/demo/page3/?name='+{item}}><Link> 

<Route path={this.props.match.url+'/page1'} component={page1}/> 
<Route path={this.props.match.url+'/page2/:myParam'} component={page2}/> 
<Route path={this.props.match.url+'/page3'} component={page3}/> 
// 关于刷新导致路由参数丢失的问题:可以考虑将内容存放在session中 

2.2 路由重定向

2.2.1 通过Redirect标签来实现

该标签在渲染时会直接触发跳转!

  • to:string
    <Redirect to="/somewhere/else" />
  • to:object
<Redirect to={{ 
  pathname: '/login', 
  search: '?utm=your+face', 
  state: { 
    referrer: currentLocation 
  } 
}} /> 

2.2.2 在Route中的render实现跳转

import { Route, Redirect } from 'react-router-dom'; 
<Route exact path="/" render={() => ( 
  loggedIn ? ( 
    <Redirect to="/dashboard" /> 
  ) : ( 
    <PublicHomePage /> 
  ) 
)} /> 

2.2.3 通过函数实现

this.props.history.push(路径)

另外:在switch组件中

// 根据匹配参数进行重定向 
<Switch> 
  <Redirect from='/users/:id' to='/users/profile/:id' /> 
  <Route path='/users/profile/:id' component={Profile} /> 
</Switch> 

注意:不加from的redirect标签会直接匹配所有请求,直接跳转;from只能写在switch组件中!

2.3 路由嵌套

顶级路由调转到页面,页面中还有二级路由进行控制跳转,如:跳转到/menu1然后,该页面左侧有列表可以跳转到/menu1/pag1/menu1/pag2/menu1/pag3。右侧有展示内容的界面,随着左侧点击路由,右侧进行改变!

注意:必须保证嵌套路由的前缀和上级路由一致!否则无法找到该路由!!!路由匹配顺序是:由外而内!当最外部无匹配路由则匹配NotFound路由,当外部匹配部分路由则进入下级路由继续依次匹配!

上面的需求可以这样分析:

  1. 在二级路由界面先拿到本界面的路由,然后拼接下一级路由(当然也可以是全新的路由,看个人习惯)
  2. 在二级路由界面需要展示的地方(如右侧)防止路由占位,当匹配到路由path时,将组件渲染到占位处
<!-- 左侧栏目-->
<Link to={this.props.match.url+'/pag1'}>pag1</Link>
<Link to={this.props.match.url+'/pag2'}>pag2</Link>
<Link to={this.props.match.url+'/pag3'}>pag3</Link>

<!-- 右侧内容-->
<Route path="/menu1/pag1" component={page1} />
<Route path="/menu1/pag2" component={page2} />
<Route path="/menu1/pag3" component={page3} />

即:this.props.math.url可以获取当前页面的的路由
注意:如果跳转匹配路由时,当前路由存在子集会匹配所有子集地址!
如: /menu1/page11/page111 还会匹配 /menu1/page11/menu1 ,故对于存在短地址的情况,使用exact属性,可以限定精确匹配

// 右侧内容
<Route exact path="/menu1/" component={page1} />
<Route path="/menu1/pag2" component={page2} />
<Route path="/menu1/pag3" component={page3} />

注意:如果想在嵌套路由中加载默认路由,只需要:

// 右侧内容
<Route path="/menu1/" component={page1} />
<Route path="/menu1/pag2" component={page2} />
<Route path="/menu1/pag3" component={page3} />

这样,默认跳转到二级路由界面时会默认加载第一个路由!

注意:当前react-router-dom版本为5.2.0,嵌套路由不再作为上级路由的children写了,必须写在路由对于组件内部!且父级路由不能是exact (˘̩̩̩ε˘̩ƪ)

// 错误写法
<Route path="/login" >
  <Route exact path="/" component={Login} />
  <Route path="/01" component={D01} />
  <Route path="/02" component={D02} />
  <Route path="/03" component={D03} />
</Route>

// 正确写法
// 一级路由
<Route path="/login" component={Login} />
// Login.jsx 二级路由
<Route path="/login/01" component={D01} />
<Route path="/login/02" component={D02} />
<Route path="/login/03" component={D03} />

2.4 switch匹配

router包中的switch可以实现只要有一条路由匹配则其余不匹配直接返回
用法: 使用switch包裹route标签

<Switch> 
	<Route path='/a/b/c' component={}/> 
	<Route path='/a/:x/:y component={}/> 
	<Route path='/a/b/:z component={}/> 
</Switch> 

如果没有switch,对于路由为:/a/b/c的地址来说,三者都会匹配,所有都会显示,即使加exact也没有用

import React from 'react'; 
import {HashRouter, Route, Switch} from 'react-router-dom'; 
import Home from '../home'; 
import Detail from '../detail'; 
const BasicRoute = () => ( 
    <HashRouter> 
        <Switch> 
            <Route exact path="/" component={Home}/> 
            <Route exact path="/detail" component={Detail}/> 
        </Switch> 
    </HashRouter> 
); 
export default BasicRoute; 

分别访问:
localhost:3000/#/
localhost:3000/#/detail
如果不使用exact则访问/detail时第一个路由会显示(子集匹配),如果不适用exact和switch则访问/detail时两个组件都会显示 (switch用于控制只匹配一个)

2.5 路由返回

this.props.history.go(-1)

2.6 路由设置默认NotFound页面

需要利用到Switch组件,当前面所有组件无匹配时,匹配到该默认组件

// 一级路由
<HashRouter>
  <Switch>
    <Route exact path="/" component={App} />
    <Route path="/login" component={Login} />
    <Route component={NotFound} />
  </Switch>
</HashRouter>

// 二级路由
<Switch>
  <Redirect exact path="/login" to="/login/01" />
  <Route path="/login/01" component={D01} />
  <Route path="/login/02" component={D02} />
  <Route path="/login/03" component={D03} />
  <Route component={NotFound} />
</Switch>

// 一般而言,为保证上级路由一致减少错误,上记路由可以使用:${props.match.url}取到,如<Route path={`${props.match.url}/01`} component={D01} />

特别注意:这里在两级路由上都配置了NotFound页面!尤其是二级路由页面,注意Redirect必须使用exact去匹配一级跳转过来的路由,否则无法正确路由

3 路由模块化

将路由配置抽离出路由组件中,让路由模块化

3.1 普通一级路由模块化

// 路由配置组件 router.js
const routes = [
	{
		path: "/",
		componnet: Home,
		exact: true
	},
	{
		path: "/user",
		componnet: User,
	},
	{
		path: "/news",
		componnet: News,
	},
]
export default routes;

在一级路由页面:

{
	routes.map((route,key)=>{
		if(route.exact) return <Route key={key} exact path={route.path} component={route.component} />
		else return  <Route key={key} path={route.path} component={route.component} />
	})
}

3.2 嵌套路由模块化

// 路由配置组件 router.js
const routes = [
	{
		path: "/",
		componnet: Home,
		exact: true
	},
	{
		path: "/user",
		componnet: User,
		routes: [
			{
				path: "/u1",
				componnet: U1,
			},
			{
				path: "/u2",
				componnet: U2,
			},
		]
	}
]
export default routes;

在一级路由页面,将子路由信息传递给子组件

{
	routes.map((route,key)=>{
		if(route.exact) return <Route key={key} exact path={route.path} render={props=><route.component {...props} routes={route.routes}} />
		else return <Route key={key} path={route.path} render={props=><route.component {...props} routes={route.routes}}
	})
}

react-router-dom:v6最新参考文章:https://zhuanlan.zhihu.com/p/431389907

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值