明明还没搞懂v5
,v6
就出了,学不动了哇。
这里总结下v6
版本的简要使用。
[v5版本链接]()
v6版本
开始
这里我们已经创建了一个空的React
项目
安装
yarn add react-router-dom
BrowserRouter
这里我们选择BrowserRouter
模式
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
Link
进入App.jsx
我们添加一些链接
/*
* @Date: 2022-02-15 19:01:38
* @LastEditors: zhangheng
* @LastEditTime: 2022-02-15 19:18:48
*/
import React, { memo } from "react";
import { Link } from "react-router-dom";
export default memo(function index() {
return (
<div>
<h1>hello react router</h1>
<Link to="/router1">router1</Link> | <Link to="/router2">router2</Link>
</div>
);
});
此时应用展示如下:
当我们点击链接后url
就会改变,当然页面不会有任何的变化。
渲染路由组件
我们创建两个组件:
在main.tsx
文件中引入,再使用Route
和Routes
:
这里注意我们在v5
是使用Switch
组件包裹路由组件,v6
则是移除了Switch
,转而使用Routes
了。
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}></Route>
<Route path="/router1" element={<Router1 />}></Route>
<Route path="/router2" element={<Router2 />}></Route>
</Routes>
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
嵌套路由
上述的案例我们点击后就只会显示对应组件的信息,破坏了布局,这时我们想在App
中展示路由组件可以按照如下修改:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="/router1" element={<Router1 />}></Route>
<Route path="/router2" element={<Router2 />}></Route>
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
当然我们需要在App
组件中去渲染要展示的组件:
使用Outlet
组件
/*
* @Date: 2022-02-15 19:01:38
* @LastEditors: zhangheng
* @LastEditTime: 2022-02-15 20:08:42
*/
import React, { memo } from "react";
import { Link, Outlet } from "react-router-dom";
export default memo(function index() {
//props/state
//redux hooks
//other hooks
//其他逻辑
return (
<div>
<h1>hello react router</h1>
<Link to="/router1">router1</Link> | <Link to="/router2">router2</Link>
<Outlet />
</div>
);
});
此时点击我们发现组件就先是在父组件中了,共用了父组件的布局。
动态路由匹配
我们修改一个链接:
/*
* @Date: 2022-02-15 19:01:38
* @LastEditors: zhangheng
* @LastEditTime: 2022-02-15 20:08:42
*/
import React, { memo } from "react";
import { Link, Outlet } from "react-router-dom";
export default memo(function index() {
//props/state
//redux hooks
//other hooks
//其他逻辑
return (
<div>
<h1>hello react router</h1>
<Link to="/router1">router1</Link> | <Link to="/router2/123">router2</Link>
<Outlet />
</div>
);
});
此时我们点击router2
链接,页面会跳转到空白,同时控制台会报出警告不匹配/router2/123
我们可以添加一个匹配项:
*
是在匹配不到其他的组件的时候就被匹配,当然这样就消除了警告,跳转到404页面了。
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="router1" element={<Router1 />}></Route>
<Route path="router2" element={<Router2 />}></Route>
<Route path="*" element={<h2>404</h2>}></Route>
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
但是我们只是想通过这个方式去传递某一个参数,比如,实际项目中/router2/123
中的123可能是变量,对应router2
中的页面只是去获得这个变量来请求获取不同的数据。所以我们要在组件匹配的path
作出修改:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";
import Router2s from "./pages/router2s";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="router1" element={<Router1 />}></Route>
<Route path="router2" element={<Router2s />}>
<Route path=":numberId" element={<Router2 />}></Route>
</Route>
<Route path="*" element={<h2>404</h2>}></Route>
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
此时点击router2/123
就会正确跳转到router2
页面了,我们再获取这个numberId
:
/*
* @Date: 2022-02-15 19:43:21
* @LastEditors: zhangheng
* @LastEditTime: 2022-02-15 20:21:57
*/
import React, { memo } from "react";
import { useParams } from "react-router-dom";
export default memo(function index() {
//props/state
//redux hooks
//other hooks
const params = useParams();
console.log(params);
//其他逻辑
return <div>这是router2组件</div>;
});
结果如下:
索引路由
我们接着上述的案例,当我们的url
为/router2/123
时,会正常显示router2
的组件,但是我们手动将url
改为router2/
此时就不会显示numberId
,我们可以使用Index Routes
来解决这个问题:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";
import Router2s from "./pages/router2s";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="router1" element={<Router1 />}></Route>
<Route path="router2" element={<Router2s />}>
<Route index element={<span>没有</span>} />
<Route path=":numberId" element={<Router2 />} />
</Route>
<Route path="*" element={<h2>404</h2>}></Route>
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
当我们跳转到/router2
后满足匹配父组件,但是没有匹配任何一个子组件就匹配index
,这种情况适用于用户还没有点击导航列表中的一个项目时,默认展示的一个组件。
v6新的变化解读
上述简单展示了v6
如何使用路由,这里我们讲解下其中的不同之处。
Routes
新的版本移除了Switch
,是因为以往的路由匹配方式依赖于你书写的路由渲染位置,而v6
要聪明的多。
这是一个官网的案例:
<Routes>
<Route path="teams/:teamId" element={<Team />} />
<Route path="teams/new" element={<NewTeamForm />} />
</Routes>
我们输入路径teams/new
就会匹配到teams/new
了,毕竟这个路径更具体。
OutLet
用于在父组件中渲染匹配到的子组件
useRoutes
这个方法可以替代以往使用的react-router-config
这个库了,将路由的配置单独放置在一个文件中,实现类似vue
配置路由的方式。
import React, { memo, useEffect } from 'react';
import { useRoutes } from 'react-router-dom';
//导入路由配置文件
import routes from './router';
function App() {
//这个钩子要写在路由组件中
const element = useRoutes(routes);
return (
<div className="App overflow-auto">{element}</div>
);
}
export default memo(App);
路由文件:
/*
* @Date: 2022-01-23 20:15:56
* @LastEditors: zhangheng
* @LastEditTime: 2022-01-31 19:12:10
*/
import React, { lazy, Suspense } from 'react';
import type { RouteObject } from 'react-router-dom';
const routes: RouteObject[] = [
{
path: '/*',
element: () => import('@/pages/main'),
children: [
{ path: '', element: () => import('@/pages/home') },
{
path: 'article/:articleId',
element: () => import('@/pages/article')
}
]
},
{
path: '/signup',
element: () => import('@/pages/signUp')
}
];
type lazyPropsType = () => Promise<{ default: React.ComponentType }>;
interface propsType {
importRoute: lazyPropsType;
}
//定义自动包裹Suspense函数
function LazyElement(props: propsType) {
const { importRoute } = props;
const LazyComponent = lazy(importRoute);
return (
<Suspense fallback={<div>路由懒加载...</div>}>
<LazyComponent />
</Suspense>
);
}
// 处理routes 如果element是懒加载,要包裹Suspense
function dealRoutes(routesArr: RouteObject[]) {
if (routesArr && Array.isArray(routesArr) && routesArr.length > 0) {
routesArr.forEach((route) => {
if (route.element && typeof route.element == 'function') {
const importRoute = route.element as lazyPropsType;
route.element = <LazyElement importRoute={importRoute} />;
}
if (route.children) {
dealRoutes(route.children);
}
});
}
}
dealRoutes(routes);
export default routes;
以上就是我目前使用到的v6
版本特性,更多的在我使用后再总结补充。