前言

eg:代表代码对照 若文章有误,欢迎读者留言反馈

withRouter高阶组件

作用:把不是通过路由切换过来的组件中,将react-router 的 history、location、match 三个对象传入props对象上

默认情况下必须是经过路由匹配渲染的组件才存在this.props,才拥有路由参数,才能使用编程式导航的写法,执行this.props.history.push(‘/uri’)跳转到对应路由的页面,然而不是所有组件都直接与路由相连的,当这些组件需要路由参数时,使用withRouter就可以给此组件传入路由参数,此时就可以使用this.props

1
2
3
4
5
// 引入withRouter
import { withRouter} from 'react-router-dom'

// 执行一下withRouter
export default withRouter(Cmp)

路由懒加载

1
2
// 箭头函数方式
component:resolve =>require(['@/component/Login'],resolve)

React-Router V6版本

React-Router V6版本常用路由组件和hooks

组件名 作用 说明
<Routes> 一组路由 代替原有<Switch>,所有子路由都用基础的Router children来表示
<Route> 基础路由 Route是可以嵌套的,解决原有V5中严格模式,后面与V5区别会详细介绍
<Link> 导航组件 在实际页面中跳转使用
<Outlet/> 自适应渲染组件 根据实际路由url自动选择组件
hooks名 作用 说明
useParams 返回当前参数 根据路径读取参数
useNavigate 返回当前路由 代替原有V5中的 useHistory
useOutlet 返回根据路由生成的element
useLocation 返回当前的location 对象
useRoutes 同Routers组件一样,只不过是在js中使用
useSearchParams 用来匹配URL中?后面的搜索参数

如表格,V6版本常用的组件和hooks,这些是新增的常用部分,不常用部分可以查看官方文档。接下来,咱们通过案例的形式来比较上面新增的那些变化。

1. 路由的基本使用

在app.js中分别搭建home和about页面路由。

v5的写法

1
2
3
4
5
6
7
8
import { HashRouter,Route,Switch } from 'react-router-dom'
......
<HashRouter>
<Switch>
<Route path="/home" component={ Home }></Route>
<Route path="/about" component={ About }></Route>
</Switch>
</HashRouter>

v6的写法

1
2
3
4
5
6
7
8
9
import { HashRouter,Route,Routes } from 'react-router-dom'
......
//Routes替换了Switch
<HashRouter>
<Routes>
<Route path="/home" element={ <Home/> }></Route>
<Route path="/about" element={ <About/> }></Route>
</Routes>
</HashRouter>

2. 嵌套路由

嵌套路由是V6版本对之前版本一个较大的升级,采用嵌套路由会智能的识别

1
2
3
4
5
6
7
8
9
......
<Routes>
<Route path="user" element={<Users />}>
// :xx除了create都是UserDetail这个页面【动态传参,可以输任意内容】
<Route path=":xx" element={<UserDetail />} />
<Route path="create" element={<NewUser />} />
</Route>
</Routes>

当访问 /user/123 的时候,组件树将会变成这样

1
2
3
4
5
<App>
<Users>
<UserDetail/>
</Users>
</App>

当访问/user/create的时候,组件树将变成这样

1
2
3
4
5
<App>
<Users>
<NewUser/>
</Users>
</App>

注意,上面写法需要在父组件中指定子组件渲染位置,<Outlet/>相当于占位符,告诉当前组件,子路由在当前位置进行渲染。

1
2
3
4
5
6
7
8
9
function Users() {
return (
<div>
<h1>Users</h1>
<Outlet />
</div>
);
}

当然除了上面写法还有另一种写法
在App.js父组件中创建一级路由

1
2
3
4
5
6
......
<Routes>
<Route path="/home/*" element={ <Home />} />
<Route path="/user" element={ <User />}/>
</Routes>

然后在Home组件中配置二级路由

1
2
3
4
5
<Routes>
{/* 嵌套路由写法 这里可以省略/home一级路由 */}
<Route path="myheader" element={ <MyHeader />}/>
<Route path="myfooter" element={ <MyFooter />}/>
</Routes>

3. 重定向和404

v5写法

1
2
3
4
5
6
// 重定向 from从哪里来 to重定向到何处去
<Redirect from="/home" to="/" />

// 404设置 可以省略path="*"
<Route component={Notfound} />

v6写法

1
2
3
4
5
6
7
import { Route,Routes,Navigate } from 'react-router-dom'
......
{/* index属性来指定默认路由/ */}
<Route index element={ <Navigate to='/home' />} />
{/* 404 path="*"不能省略 */}
<Route path="*" element={ <NotFind /> } />

4. 路由传参

由于v6版本已经废弃withRouter这个高阶函数,所以类组件获取路由对象可以通过封装高阶组件的方式来创建出来withRouter这个函数,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import {useLocation,useNavigate,useParams} from "react-router-dom";
// 封装新的withRouter高阶函数
export function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component {...props} router={{ location, navigate, params }} />
);
}
return ComponentWithRouterProp;
}

v6版本React路由传参方式有三种:

Ø 动态路由参数(param)

以"/detail/:id"形式传递的数据

​ 类组件通过如下方法得到

1
2
// 首先当前组件先使用高阶组件withRouter,然后就可以像v5一样使用了。
this.props.router.match.params

函数组件可以通过如下方法跳转并传参

1
2
3
4
5
6
7
import { useNavigate,useParams,useLocation } from 'react-router-dom' 
......
const navigate = useNavigate()
navigate('/detail/:id') // 跳转方法
const params = useParams()
params.id // 获取参数

Ø 查询字符串(query)

通过地址栏中的 home?key=value&key=value传递

类组件通过如下方法得到

1
2
// 首先当前组件先使用高阶组件withRouter,然后就可以像v5一样使用了。
this.props.router.location.search

函数组件可以通过如下方法跳转并传参

1
2
3
4
5
6
7
import { useNavigate,useParams,useLocation } from 'react-router-dom' 
......
const navigate = useNavigate()
navigate('/detail?key=value') // 跳转方法
const location = useLocation()
location.search // 获取参数

Ø 隐式传参(state),通过地址栏是观察不到的

通过路由对象中的state属性进行数据传递

类组件通过如下方法得到

1
2
// 首先当前组件先使用高阶组件withRouter,然后就可以像v5一样使用了。
this.props.router.location.state

函数组件可以通过如下方法跳转并传参

1
2
3
4
5
6
7
import { useNavigate,useParams,useLocation } from 'react-router-dom' 
......
const navigate = useNavigate()
navigate('/detail',{state={ key: value }}) // 跳转方法
const location = useLocation()
location.state // 获取参数

5.useRoutes 替换react-router-config

我们在App.js中通过useRoutes这个hooks来搭配路由。如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export default function App1() {
let element = useRoutes([
{ path: "/", element: <Home /> },
{
path: "user",
element: <User />,
children: [
{ path: ":id", element: <User2 /> },
{ path: "user1", element: <User1 /> }
]
},
{ path: "*", element: <NotFound /> }
]);
return <>
// 这里把上面使用hooks配置的全局路由在这里执行以下
{ element }
</>
}