在 SPA 中,页面跳转,实际上只是在切换组件。切换组件时,我们需要通过路由来管理浏览器 URL 与组件之间的映射关系。
- React Router
React 官方并没有提供对应的路由插件,因此我们选择了第三方的路由插件:React Router。
版本 React Router 最新的版本是 v6,以v5 的版本为例。
- 创建 React 项目
create-react-app react-peoject
npx create-react-app react-peoject - 下载路由
npm i react-router-dom@5.3.0
yarn add react-router-dom@5.3.0
1.React 中的路由是直接在组件中进行配置。
-
路由分类
React 中的路由也可以分为 hash 模式和 history 模式两种,分别对应的组件是 和 。 -
基础配置
因为任何一个 React 项目,默认渲染的组件都是 App.js,所以,我们的一级路由,就在 App.js 进行配置。
// 通过路由依赖包,引入相关组件
import { HashRouter, Switch, Route } from 'react-router-dom';
// 引入路由对应的页面组件
import Login from './pages/login/Login.jsx'
import Register from './pages/register/Register.jsx';
export default function App() {
return (
<HashRouter>
<Switch>
<Route path="/login" component={Login}></Route>
<Route path="/register" component={Register}></Route>
</Switch>
</HashRouter>
)
}
2.其他配置
- 精确匹配
<Route exact path="/" component={Home}></Route>
- 重定向
import { HashRouter, Switch, Route, Redirect } from 'react-router-dom';
export default function App() {
return (
<HashRouter>
<Switch>
{/* 重定向 */}
<Redirect exact from='/' to="/home"></Redirect>
<Route path="/home" component={Home}></Route>
</Switch>
</HashRouter>
)
}
- 路由懒加载
import React from 'react'
export default function App() {
return (
<React.Suspense fallback={<h1>加载中...</h1>}>
<HashRouter>
// ....
</HashRouter>
</React.Suspense>
)
}
通过懒加载的方式引入组件:
const Register = React.lazy(() => import('./pages/register/Register'));
注:import 必须在所有代码之前,通过懒加载引入的组件必须卸载 import 引入的组件之后。
3.路由跳转
React 中的路由跳转分为了两种方式:
组件跳转
事件跳转
一、组件跳转
import { Link, NavLink } from 'react-router-dom';
export default class Login extends Component {
render() {
return (
<div>
<h1>用户登录</h1>
<Link to="/register">没有账号?去注册</Link>
<NavLink to="/register" activeClassName='active'>没有账号?去注册</NavLink>
</div>
)
}
}
二、事件跳转
this.props.history.push('/login');
this.props.history.replace('/home');
三、非路由组件
应用中的组件,不是通过路由加载进来并渲染的,这一类组件,我们称之为“非路由组件”。这一类组件的 props
身上,就无法接收到路由相关的属性和方法。高阶组件 withRouter 我们可以将一个非路由组件,传递给 withRouter,在 withRouter
内部,会对非路由组件的功能进行加强处理,然后返回一个升级版的组件,处理后的组件身上就可以重新获取到路由相关的属性和方法。
import { withRouter } from 'react-router-dom'
class HomeHeader extends Component {
render() {
return (
<div>
// ...
</div>
)
}
}
export default withRouter(HomeHeader)
4.二级路由
React 中二级路由的配置和一级路由的配置基本上一致。
一、配置二级路由
import { Switch, Route } from 'react-router-dom';
<Switch>
{/* 和浏览器的 URL 地址进行匹配 */}
<Route path="/home/counter" component={Counter}></Route>
<Route path="/home/todoList" component={TodoList}></Route>
</Switch>
二、二级路由的配置位置
React 中的路由配置,不像 Vue 全都同一写在一个配置文件中。
React 中的路由配置,是根据组件渲染的位置来决定的,我们希望这个路由组件渲染在什么位置,我们就把这个路由配置写在什么位置。
例如我们想在首页中渲染计数器组件和待办事项组件:
export default class Home extends Component {
render() {
return (
<div>
<ul>
<li>计数器</li>
<li>TodoList</li>
</ul>
<div>
<Switch>
{/* 和浏览器的 URL 地址进行匹配 */}
<Route path="/home/counter" component={Counter}></Route>
<Route path="/home/todoList" component={TodoList}></Route>
</Switch>
</div>
</div>
)
}
}
三、二级路由跳转
二级路由跳转的方式也和一级路由一样,组件跳转或事件跳转都可以。唯一要注意的就是跳转的时候需要将一二级路径写完整:
<ul>
{/* 改变浏览器 URL 的地址 */}
<li><NavLink activeClassName='active' to="/home/counter">计数器</NavLink></li>
<li><NavLink activeClassName='active' to="/home/todoList">TodoList</NavLink></li>
</ul>
5.路由传参
一、动态路由(params 传参)
1、传递数据
<link to="/路径/参数">
2、配置动态路由
<Route path="/路径/:变量名" component={组件}>
3、组件接收参数
this.props.match.params.变量名
二、query 传参
1、传递参数
this.props.history.push({
pathname: '/路径',
query: {
参数名: 参数值
}
})
2、接收参数
this.props.lacation.query.变量名
-
缺点:页面刷新后数据就不存在了。
-
优点:参数不会在浏览器的 URL 中显示出来。
三、state 传参
1、传递参数
this.props.history.push({
pathname: '/路径',
state: {
参数名: 参数值
}
})
2、接收参数
this.props.lacation.state.变量名
- 缺点:页面刷新后数据就不存在了。
- 优点:参数不会在浏览器的 URL 中显示出来。
四、search 传参
1、传递参数
<link to="/路径?参数名=参数值">
2、接收参数
this.props.location.search
- 优点:页面刷新后数据还保存
- 缺点:获取到的数据格式处理起来很麻烦