大家好,我是 CoderBin
一、React-Router 介绍及说明
介绍:想了解更多详细知识,可前往 React-Router中文网
引用:组件是 React 的核心功能,其拥有非常强大的声明式编程模型。React Router 是导航组件的集合,可与你的应用程序进行声明式的组合。无论你是想为你的 Web 应用程序添加书签,还是在 React Native 中进行组件化导航,React Router 都可以在 React 的任何位置渲染使用 - 所以请考虑使用!
React-Router 有三个版本,分别是:WEB、NATIVE、CORE,对于web开发人员来说,选择 WEB 版进行学习即可
二、React-Router5 安装
学习 React-Router5 需要安装 React 提供的第三方库:react-router-dom
npm install --save react-router-dom@5
三、路由的基本使用 - Link组件
1. 路由的使用步骤
- 在组件中导入对应路由链接组件,并设置路由链接
- 在组件中导入 Route 渲染组件,注册路由
- 在 index.js 中导入路由组件,在
<App> 的最外侧包裹一个 <BrowserRouter> 或 <HashRouter>
<BrowserRouter> 表示 history 模式的路由<HashRouter> 表示 Hash 模式的路由
2. Link 介绍与属性
介绍:在应用程序周围提供声明式的,可访问的导航。无论你在何处渲染一个 <Link> ,都会在应用程序的 HTML 中渲染锚 (<a> )。
Link 组件的属性:
- to:string — 链接位置的字符串表示,通过连接位置的路径名,搜索和 hash 属性创建。
- to:Object — 一个可以具有以下任何属性的对象:
pathname : 表示要链接到的路径的字符串。search : 表示查询参数的字符串形式。hash : 放入网址的 hash,例如 #a-hash 。state : 状态持续到 location 。 - replace:bool — 如果为
true ,则单击链接将替换历史堆栈中的当前入口,不存在历史记录
代码示例:App.jsx
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
export default class App extends Component {
render() {
return (
<div>
{}
<Link to="/home">Home</Link>
<Link to="/about" replace>About</Link>
{}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
)
}
}
index.js
import { createRoot } from "react-dom/client";
import App from './App'
import {BrowserRouter} from 'react-router-dom'
const root = createRoot(document.getElementById('root'))
root.render(
<BrowserRouter>
<App/>
</BrowserRouter>
)
四、路由组件和一般组件
1. 写法不同
- 一般组件
<Demo> - 路由组件
<Route path="/demo" component={Demo}/>
2. 存放位置不同
- 一般组件:components
- 路由组件:pages 或 views
3. 接收到的props不同
-
一般组件:写组件标签时传递了什么,就能收到什么 -
路由组件:接收到三个固定的属性
-
history:一些编程式导航的方法 push()、replace()、goForward()、go()、goBack() 等 -
location:当前路由的一些信息,参数。pathname、search、state 等 -
match:当前路由的一些信息,参数。path、url、params 等
五、NavLink 组件的使用
介绍:一个特殊版本的 Link,当它与当前 URL 匹配时,为其渲染元素添加样式属性。
NavLink 组件的属性:
- activeName:string — 要给出的元素的类处于活动状态时。默认的给定类是
active 。它将与 className 属性一起使用。 - activeStyle:Object — 当元素处于
active 时应用于元素的样式
代码示例 App.jsx
import React, { Component } from 'react'
import { NavLink, Route } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
export default class App extends Component {
render() {
return (
<div>
{}
<NavLink activeClassName='coder' to="/about">About</NavLink>
<NavLink activeStyle={{color: 'red'}} to="/home">Home</NavLink>
{}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
)
}
}
六、封装NavLink 组件
代码示例:src/components/MyNavLink/index.jsx
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
export default class MyNavLink extends Component {
render() {
console.log(this.props);
return (
<NavLink activeClassName='coder' {...this.props} />
)
}
}
App.jsx
import React, { Component } from 'react'
import { Route } from 'react-router-dom'
import MyNavLink from './components/MyNavLink'
import Home from './pages/Home'
import About from './pages/About'
export default class App extends Component {
render() {
return (
<div>
{}
{}
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">
<div>Coderbin</div>
</MyNavLink>
{}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
)
}
}
七、Switch 组件的使用
介绍:渲染与该地址匹配的第一个子节点 <Route> 或者 <Redirect> 。
代码示例:App.jsx
import React, { Component } from 'react'
import { NavLink, Route, Switch } from 'react-router-dom'
import MyNavLink from './components/MyNavLink'
import Home from './pages/Home'
import About from './pages/About'
export default class App extends Component {
render() {
return (
<div>
{}
<NavLink to="/about">About</NavLink>
<NavLink to="/home">Home</NavLink>
{}
{}
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
{}
{}
<Route path="/home" component={Test}/>
</Switch>
</div>
)
}
}
八、路由懒加载
1. 路由组件的lazyLoad
import React, { Component, lazy, Suspense } from 'react'
import { NavLink, Route } from 'react-router-dom'
const Home = lazy(() => import('./Home'))
const About = lazy(() => import('./About'))
export default class Lazyload extends Component {
render() {
return (
<div>
{}
<NavLink to='/home'>home</NavLink>
<NavLink to='/about'>about</NavLink>
{}
{}
{}
<Suspense fallback={<h1>loading...</h1>}>
<Route path="/home" component={Home}/>
<Route path="/about" component={About}/>
</Suspense>
</div>
)
}
}
九、解决多级路径刷新页面样式丢失的问题
-
public/index.html 中 引入样式时不写 ./ 写 / (常用) -
public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用) -
使用HashRouter
十、路由的严格匹配与模糊匹配
-
默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致) -
开启严格匹配:<Route exact={true} path="/about" component={About}/> -
严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
十一、Redirect 组件的使用
介绍:渲染 <Redirect> 将使导航到一个新的地址。这个新的地址会覆盖 history 栈中的当前地址,类似服务器端(HTTP 3xx)的重定向。
Redirect 组件的属性:
- to:string — 重定向到的 URL,可以是任何
path-to-regexp 能够理解有效 URL 路径。在 to 中使用的 URL 参数必须由 from 覆盖。
<Redirect to="/somewhere/else" />
- to:Object — 重定向到的 location,
pathname 可以是任何 path-to-regexp 能够理解的有效的 URL 路径。
<Redirect to={{pathname: "/login", search:"?utm=your+face", state:{ referrer: currentLocation }}}/>
- push:bool — 当为
true 时,重定向会将新地址推入 history 中,而不是替换当前地址。 <Redirect push to="/somewhere/else" />
Redirect 组件的使用:
- 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
代码示例:Appjsx
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
十二、嵌套路由的使用方法
使用嵌套路由的注意点:
- 嵌套路由的第一级路由在注册时,不可以写 exact 严格匹配 !
- 设置嵌套路由链接写 to 属性值时:二级路由的路径前要加一级路由的路径
- 注册嵌套路由写 path属性值时:要与路由链接的 to 属性值保持一致
代码示例:Home.jsx
import React, { Component } from 'react'
import { NavLink, Route, Switch, Redirect } from 'react-router-dom'
import News from './News'
import Message from './Message'
export default class Home extends Component {
render() {
return (
<div>
<h3>我是 Home 的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
{}
{}
<NavLink to="/home/news">News</NavLink>
</li>
<li>
<NavLink className="list-group-item" to="/home/message">Message</NavLink>
</li>
</ul>
{}
<Switch>
{}
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message} />
<Redirect to="/home/news"/>
</Switch>
</div>
</div>
)
}
}
十三、向路由组件传递参数
1. 向路由组件传递 params 参数
使用步骤:
- 路由链接(携带参数):
<Link to='/demo/test/tom/18'}>详情</Link> - 注册路由(声明接收):
<Route path="/demo/test/:name/:age" component={Test}/> - 接收参数:
this.props.match.params
代码示例:Message.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: '01', title: '消息1'},
{id: '02', title: '消息2'},
{id: '03', title: '消息3'}
]
}
render() {
return (
<div>
<ul>
{
this.state.messageArr.map(message => {
return (
<li key={message.id}>
{}
{}
<Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link>
</li>
)
})
}
</ul>
{}
<Route path="/home/message/detail/:id/:title" component={Detail}/>
</div>
)
}
}
Detail.jsx
import React, { Component } from 'react'
const detialData = [
{id: '01', content: '你好,中国'},
{id: '02', content: '你好,React'},
{id: '03', content: '你好,React-Router'}
]
export default class Detail extends Component {
render() {
const { id, title } = this.props.match.params
const detail = detialData.find(item => item.id === id)
return (
<ul>
<li>ID: { id }</li>
<li>TITLE: { title }</li>
<li>CONTENT: { detail.content }</li>
</ul>
)
}
}
2. 向组件传递 search 参数
使用步骤:
- 路由链接(携带参数):
<Link to='/demo/test?name=tom&age=18'}>详情</Link> - 注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Test}/> - 接收参数:
this.props.location.search - 注意:获取到的 search 是urlencoded 编码字符串,需要借助 qs 解析
代码示例:Message.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: '01', title: '消息1'},
{id: '02', title: '消息2'},
{id: '03', title: '消息3'}
]
}
render() {
return (
<div>
<ul>
{
this.state.messageArr.map(message => {
return (
<li key={message.id}>
{}
{}
<Link to={`/home/message/detail/?id=${message.id}&title=${message.title}`}>{message.title}</Link>
</li>
)
})
}
</ul>
{}
<Route path="/home/message/detail" component={Detail}/>
</div>
)
}
}
Detail.jsx
import React, { Component } from 'react'
import qs from 'qs'
const detialData = [
{id: '01', content: '你好,中国'},
{id: '02', content: '你好,React'},
{id: '03', content: '你好,React-Router'}
]
export default class Detail extends Component {
render() {
const { search } = this.props.location
const { id, title } = qs.parse(search.slice(1))
const detail = detialData.find(item => item.id === id)
return (
<ul>
<li>ID: { id }</li>
<li>TITLE: { title }</li>
<li>CONTENT: { detail.content }</li>
</ul>
)
}
}
3. 向组件传递 state 参数
使用步骤:
- 路由链接(携带参数):
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link> - 注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Test}/> - 接收参数:
this.props.location.state - 注意:刷新也可以保留住参数
代码示例:Message.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: '01', title: '消息1'},
{id: '02', title: '消息2'},
{id: '03', title: '消息3'}
]
}
render() {
return (
<div>
<ul>
{
this.state.messageArr.map(message => {
return (
<li key={message.id}>
{}
{}
<Link to={{pathname:'/home/message/detail',state:{id:message.id,title:message.title}}}>{message.title}</Link>
</li>
)
})
}
</ul>
{}
<Route path="/home/message/detail" component={Detail}/>
</div>
)
}
}
Detail.jsx
import React, { Component } from 'react'
const detialData = [
{id: '01', content: '你好,中国'},
{id: '02', content: '你好,React'},
{id: '03', content: '你好,React-Router'}
]
export default class Detail extends Component {
render() {
const { id, title } = this.props.location.state || {}
const detail = detialData.find(item => item.id === id) || {}
return (
<ul>
<li>ID: { id }</li>
<li>TITLE: { title }</li>
<li>CONTENT: { detail.content }</li>
</ul>
)
}
}
十四、编程式路由导航
介绍:借助this.prosp.history对象上的API对操作路由跳转、前进、后退
- this.prosp.history.push()
- this.prosp.history.replace()
- this.prosp.history.goBack()
- this.prosp.history.goForward()
- this.prosp.history.go()
代码示例:Detail.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: '01', title: '消息1'},
{id: '02', title: '消息2'},
{id: '03', title: '消息3'}
]
}
pushShow = (id, title) => {
this.props.history.push({pathname:'/home/message/detail', state:{id, title}})
}
replaceShow = (id, title) => {
return () => {
this.props.history.replace({pathname:'/home/message/detail', state:{id, title}})
}
}
forward = () => {
this.props.history.goForward()
}
back = () => {
this.props.history.goBack()
}
go = () => {
this.props.history.go(2)
}
render() {
return (
<div>
<ul>
{
this.state.messageArr.map(message => {
return (
<li key={message.id}>
{}
{}
{}
{}
<Link to={{ pathname: '/home/message/detail', state: { id: message.id, title: message.title } }}>{message.title}</Link>
<button onClick={()=>this.pushShow(message.id, message.title)}>push查看</button>
<button onClick={this.replaceShow(message.id, message.title)}>replace查看</button>
</li>
)
})
}
</ul>
{}
{}
<Route path="/home/message/detail" component={Detail}/>
<button onClick={ this.forward }>前进</button>
<button onClick={ this.back }>后退</button>
<button onClick={ this.go }>go</button>
</div>
)
}
}
十五、withRouter 的使用
介绍:您可以通过 withRouter 高阶组件访问 history 对象的属性和最近的 <Route> 的 match 。 当路由渲染时, withRouter 会将已经更新的 match , location 和 history 属性传递给被包裹的组件。
其实就是让普通组件也具备路由组件所特有的 API
代码示例:Header.jsx
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom';
class Header extends Component {
forward = () => {
console.log('forward');
this.props.history.goForward()
}
back = () => {
console.log('back');
this.props.history.goBack()
}
go = () => {
console.log('go');
this.props.history.go(2)
}
render() {
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={ this.forward }>前进</button>
<button onClick={ this.back }>后退</button>
<button onClick={ this.go }>go</button>
</div>
)
}
}
export default withRouter(Header)
十六、BrowserRouter与HashRouter的区别
1. 底层原理不一样
- BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
- HashRouter使用的是URL的哈希值。
2. path表现形式不一样
- BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
- HashRouter的路径包含#,例如:localhost:3000/#/demo/test
3. 刷新后对路由state参数的影响
- (1).BrowserRouter没有任何影响,因为state保存在history对象中。
- (2).HashRouter刷新后会导致路由state参数的丢失!!!
4. 备注: HashRouter可以用于解决一些路径错误相关的问题。
每文一句:夫学须志也,才须学也。非学无以广才,非志无以成。
本次的分享就到这里,如果本章内容对你有所帮助的话可以点赞+收藏。文章有不对的地方欢迎指出,有任何疑问都可以在评论区留言。希望大家都能够有所收获,大家一起探讨、进步!
|