day-084-eighty-four-20230603-react路由导航-路由传参-react-router-dom的V6版本
react路由导航
编码式导航
-
编码式导航:基于JavaScript实现路由的跳转。
-
编码式导航:基于JavaScript实现路由的跳转。实际上是基于props中history对象中的相关方法实现路由跳转的。
-
在路由当中:
- 受控组件:受路由管控的组件,也就是基于Route组件进行路由匹配而渲染的组件。
- 非受控组件:不是基于Route组件匹配渲染的组件。
-
在react-router-dom的V5版本中:
-
如果是受控组件,则路由内容,会给每个组件传递三个属性:
-
history 提供了路由跳转的方式。
- push:
跳转路由
与新增历史记录
。 - replace:
跳转路由
与替换当前的历史记录
。 - go:跳转到
历史记录中指定位置
。 - goBack:回退一步 -> go(-1);
- goForward:前进一步 -> go(1);
- …
- push:
-
location:记录当前路由的信息。
- pathname:当前路由地址。
- search:当前路由的问号传参信息。
- state:当前路由的隐式传参信息。
- …
-
match:记录当前路由匹配的规则与匹配记录。
- params:存储匹配的路径参数信息。
- …
-
-
如果是非受控组件,默认不会传递这三个属性。
- 这样就有一个问题:在非受控组件中,如何实现编程式导航?
-
基于路由内部提供的
withRouter()高阶组件
,把非受控组件
变为受控组件
。- 或者说让
非受控组件
,也具备这三个属性信息,可适用于任何类型的组件
。
import { withRouter } from "react-router-dom"; const CommonMenu = function CommonMenu(props) { console.log(`CommonMenu-props`, props); return <div></div> } export default withRouter(CommonMenu);
- 或者说让
-
基于路由提供的
useHistory()
/useLocation()
/useParams()
/useRouteMatch()
等Hook函数,在函数组件中获取对应的信息!useHistory()
->history对象
。useLocation()
->location对象
。useRouteMatch()
->match对象
。useParams()
-> 获取基于路径传参的信息。
- 以上知识,必须有一个前提:所处理的组件,不管是受控还是非受控,必须都在
HashRouter()
/BrowserRouter()
等Router的内部!
-
- 这样就有一个问题:在非受控组件中,如何实现编程式导航?
-
路由传参
- 路由跳转传参的方式:
- 例如从A组件跳转到B组件,需要给B组件传递一些参数信息。
-
基于
问号传参
传递信息。- 传递的信息在
URL地址栏
中可以看见(明文)。丑
、不安全
、有长度限制
。
- 传递的信息都要变为
urlencoded格式字符串
,接收的时候也需要处理这样的字符串。- 可以基于
qs库
或者new URLSearchParams()
处理。
- 可以基于
- 在
跳转后的目标组件
进行刷新操作
,因为传递的信息
在地址栏中有,所以依然可以获取问号传参信息
。
- 传递的信息在
-
基于
隐式传参
传递信息。传递的信息
在URL地址栏
中看不见。不丑
、安全
、没有长度限制
。
- 可以传递任何格式的数据。
- 在
跳转后的目标组件
进行刷新操作
,因为地址栏
中没有传递的信息
,那么之前传递的信息
就消失了。
-
基于
路径参数
传递信息,把传参信息
作为地址的一部分
。- 和
问号传参
一样,也是要把传递的信息
放在URL地址栏
中,所以相关特点和问号传参几乎一致。- 只不过这种模式看上去比
问号传参
美观一些。
- 只不过这种模式看上去比
- 步骤:
- 第一步:修改路由匹配的规则。
path: '/home/message'
旧写法。path: '/home/message/:lx?/:name?'
新写法。:
说明是传递的参数。?
可传可不传。
- 第二步:跳转的时候,把需要传递的值,作为地址的一部分;接收信息的时候,基于
match.params
/useParams()
处理即可!
- 第一步:修改路由匹配的规则。
- 和
-
- 例如从A组件跳转到B组件,需要给B组件传递一些参数信息。
对问号传参的urlencoded格式字符串信息处理
路由懒加载
-
默认情况下,我们会把所有组件的代码全部打包到一个js文件中-即主js文件。这样当页面第一次渲染的时候,需要从服务器获取这个主js文件才能执行,但是因为其文件过大,需要加载很长时间,在此期间内,页面呈现白屏。
- 为了加快页面第一次渲染的速度,我们只把默认需要展示的组件打包到主js文件中,让主js文件小一些,其余组件的代码单独打包到别的js文件中,刚开始加载页面的时候不加载这些代码。
- 当基于路由切换,需要加载某个组件的时候,再动态的从服务器获取对应的js文件或对应的代码,进行渲染!
- 我们把以上这种优化手段,称之为路由懒加载。
- 这个是前端必做的性能优化之一。
- 为了加快页面第一次渲染的速度,我们只把默认需要展示的组件打包到主js文件中,让主js文件小一些,其余组件的代码单独打包到别的js文件中,刚开始加载页面的时候不加载这些代码。
-
路由懒加载步骤:
- 基于React.lazy、ES6中的import函数、/webpackChunkName:‘home’/,保证webpack打包后的时候,可以把各个组件代码打包到不同的js文件中!页面渲染的时候,最开始只加载主js文件。
- 路由切换时,会再加载其它基于webpackChunkName的的js文件。
- 基于React.Suspense来处理动态加载的组件或异步组件,只有这样才能把异步组件中加载出来。
- fallback: 在异步组件没有渲染出来之前,先展示fallback中的信息,异步组件渲染出来后,fallback中的信息就会销毁!
- 基于React.lazy、ES6中的import函数、/webpackChunkName:‘home’/,保证webpack打包后的时候,可以把各个组件代码打包到不同的js文件中!页面渲染的时候,最开始只加载主js文件。
-
在jsx文件及js代码中,使用src引入文件如图片这类需要使用文件地址时,要先用ES6把相对路径的文件导入进来再引用。或者使用绝对路径。
-
在css或less时,使用图片这类需要使用文件地址时,是可以直接使用相对路径的。
组件封装-loading
react-router-dom的V6版本
react路由V6版本-基础版文件结构
- 文件结构
- React阶段/day0603_router6/src/index.jsx
- React阶段/day0603_router6/src/App.jsx 构建一级路由
- React阶段/day0603_router6/src/layout 布局类组件放置处,实际上这里放的大多为一级路由对应的组件。
- 因为布局类的文件大多是一级路由对应的组件。
- 个人2023年感觉很多项目是这样拆分的,这样可以让文件更明确些。
- 个人做过的项目和参考的项目大多是这样布置的。
- 理论上,也都可以全部放在views文件夹下。
- 放在这里,也可以让项目层级减少一层。
- 这个理论上可以凭个人喜好来。
- React阶段/day0603_router6/src/layout/BasicLayout.jsx
- React阶段/day0603_router6/src/layout/Error.jsx
- React阶段/day0603_router6/src/layout/UserLayout.jsx
- React阶段/day0603_router6/src/views 页面组件,一般是二级及以下的业务组件。
- React阶段/day0603_router6/src/views/home 二级路由组件-Home.jsx下的三级路由组件。
- React阶段/day0603_router6/src/views/home/Message.jsx
- React阶段/day0603_router6/src/views/home/Watch.jsx
- React阶段/day0603_router6/src/views/home/Worker.jsx
- React阶段/day0603_router6/src/views/Category.jsx
- React阶段/day0603_router6/src/views/Home.jsx
- React阶段/day0603_router6/src/views/Login.jsx
- React阶段/day0603_router6/src/views/Personal.jsx
- React阶段/day0603_router6/src/views/Register.jsx
- React阶段/day0603_router6/src/views/home 二级路由组件-Home.jsx下的三级路由组件。
react路由V6版本-基础版路由代码
- 文件结构
-
React阶段/day0603_router6/src/index.jsx
import React from "react"; import ReactDOM from "react-dom/client"; /* ANTD */ import { ConfigProvider } from "antd"; import zhCN from "antd/locale/zh_CN"; /* 组件&样式 */ import "./index.less"; import App from "./App"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <ConfigProvider locale={zhCN}> <App /> </ConfigProvider> );
-
React阶段/day0603_router6/src/App.jsx 主视图文件,构建一级路由。
import React from "react"; // 1. 引入HashRouter, Routes, Route, Navigate等react-router-dom提供的组件。引入HashRouter用于把组件包起来,Routes用于设置路由信息组-把多条路由信息组合成一组以便只渲染一个路由视图,Route用于设置单条路由信息,Navigate用于与Route配合起来设置重定向。 import { HashRouter, Routes, Route, Navigate } from "react-router-dom"; // 2. 引入路由需要用到的业务视图组件。 import BasicLayout from "./layout/BasicLayout"; import UserLayout from "./layout/UserLayout"; import Error from "./layout/Error"; import Login from "./views/Login"; import Register from "./views/Register"; import Home from "./views/Home"; import Personal from "./views/Personal"; import Category from "./views/Category"; import Watch from "./views/home/Watch"; import Worker from "./views/home/Worker"; import Message from "./views/home/Message"; const App = function App() { // 3. 构建路由。 return ( <HashRouter> <Routes> <Route path="/" element={<BasicLayout />}> <Route path="" element={<Navigate to="/home" />} /> <Route path="home" element={<Home />}> <Route path="" element={<Navigate to="/home/watch" />} /> <Route path="watch" element={<Watch />} /> <Route path="worker" element={<Worker />} /> <Route path="message" element={<Message />} /> </Route> <Route path="category" element={<Category />} /> <Route path="personal" element={<Personal />} /> </Route> <Route path="/user" element={<UserLayout />}> <Route path="" element={<Navigate to="/user/login" />} /> <Route path="login" element={<Login />} /> <Route path="register" element={<Register />} /> </Route> <Route path="/404" element={<Error />} /> <Route path="*" element={<Navigate to="/404" />} /> </Routes> </HashRouter> ); }; export default App;
-
React阶段/day0603_router6/src/layout
-
React阶段/day0603_router6/src/layout/BasicLayout.jsx 一级路由组件。
import { useState } from "react" import { Menu, Button } from "antd" import { HomeOutlined, ClusterOutlined, UserOutlined, MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons' import styled from "styled-components" import logo from "@/assets/images/logo.svg" import avatar from "@/assets/images/touxiang.png" import { Outlet } from "react-router-dom" /* 组件样式 */ const BasicLayoutStyle = styled.div` height: 100%; overflow: hidden; .header{ box-sizing: border-box; padding: 0 15px; height: 48px; background: #001529; display: flex; justify-content: space-between; align-items: center; .logo, .info{ line-height: 48px; font-size: 18px; color: #FFF; display: flex; align-items: center; img{ margin-right: 10px; width: 35px; height: 35px; } } .info{ font-size: 14px; img{ width: 30px; height: 30px; } } } .content{ height: calc(100% - 48px); display: flex; .menu-box{ height: 100%; background: #001529; .ant-btn{ margin-left: 4px; background: transparent; box-shadow: none; } .ant-menu-item{ padding: 0 24px; } .ant-menu-inline-collapsed{ .ant-menu-item{ padding: 0 28px; } } } .view-box{ box-sizing: border-box; padding: 15px; height: 100%; flex-grow: 1; .component{ height: 100%; overflow-y: auto; overflow-x: hidden; background: #FFF; } } } ` const BasicLayout = function BasicLayout() { // 左侧Menu的数据 const menuItem = [{ key: 'home', label: '控制面板', icon: <HomeOutlined /> }, { key: 'category', label: '分类管理', icon: <ClusterOutlined /> }, { key: 'personal', label: '个人中心', icon: <UserOutlined /> }] // 定义状态 let [collapsed, setCollapsed] = useState(false) return <BasicLayoutStyle> <div className="header"> <h2 className="logo"> <img src={logo} alt="" /> Ant Design </h2> <div className="avatar"> <p className="info"> <img src={avatar} alt="" /> 海贼王-路飞 </p> </div> </div> <div className="content"> <div className="menu-box"> <Button type="primary" onClick={() => { setCollapsed(!collapsed) }}> {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} </Button> <Menu mode="inline" theme="dark" items={menuItem} defaultSelectedKeys={['home']} inlineCollapsed={collapsed} /> </div> <div className="view-box"> <div className="component"> {/* 主页的二级路由 */} <Outlet /> </div> </div> </div> </BasicLayoutStyle> } export default BasicLayout
-
React阶段/day0603_router6/src/layout/Error.jsx 一级路由组件。
import React from "react"; import { Button, Empty } from "antd"; import styled from "styled-components"; /* 组件的样式 */ const ErrorStyle = styled.div` height: 100%; overflow: hidden; .ant-empty { position: relative; top: 100px; } `; const Error = function Error() { return ( <ErrorStyle> <Empty description={<span>很遗憾,您访问的页面不存在!</span>}> <Button type="primary">返回首页</Button> </Empty> </ErrorStyle> ); }; export default Error;
-
React阶段/day0603_router6/src/layout/UserLayout.jsx 一级路由组件。
import React from "react"; import { Tabs } from "antd"; import styled from "styled-components"; import backgroundImg from "@/assets/images/background.svg"; import logo from "@/assets/images/logo.svg"; import { Outlet } from "react-router-dom"; /* 组件样式 */ const UserLayoutStyle = styled.div` position: relative; height: 100%; background: url(${backgroundImg}) no-repeat; background-size: 100%; .content { position: absolute; top: 100px; left: 50%; margin-left: -165px; width: 330px; } .header { .title { display: flex; justify-content: center; align-items: center; line-height: 44px; font-size: 33px; font-weight: normal; img { margin-right: 10px; width: 44px; height: 44px; } } .subtitle { margin: 12px 0 40px 0; text-align: center; font-size: 14px; color: rgba(0, 0, 0, 0.45); } } .ant-tabs { margin-bottom: 10px; .ant-tabs-nav { &:before { border-bottom-color: #ddd; } } .ant-tabs-tab { padding: 0 10px; font-size: 16px; line-height: 40px; } } `; const UserLayout = function UserLayout() { // Tab页卡的数据 const tabItem = [ { label: `用户登录`, key: "login", }, { label: `用户注册`, key: "register", }, ]; return ( <UserLayoutStyle> <div className="content"> <div className="header"> <h1 className="title"> <img src={logo} alt="" /> <span>Ant Design</span> </h1> <p className="subtitle"> Ant Design 是西湖区最具影响力的 Web 设计规范 </p> </div> <Tabs centered defaultActiveKey="login" items={tabItem} /> {/* 登录/注册二级路由的位置 */} <Outlet /> </div> </UserLayoutStyle> ); }; export default UserLayout;
-
-
React阶段/day0603_router6/src/views 页面组件,一般是二级及以下的业务组件。
-
React阶段/day0603_router6/src/views/home 二级路由组件-Home.jsx下的三级路由组件。
-
React阶段/day0603_router6/src/views/home/Message.jsx
import React from "react"; const Message = function Message() { return <div>控制面板 - 消息中心</div>; }; export default Message;
-
React阶段/day0603_router6/src/views/home/Watch.jsx
import React from "react"; const Watch = function Watch() { return <div>控制面板 - 数据监控</div>; }; export default Watch;
-
React阶段/day0603_router6/src/views/home/Worker.jsx
import React from "react"; const Worker = function Worker() { return <div>控制面板 - 工作台</div>; }; export default Worker;
-
-
React阶段/day0603_router6/src/views/Category.jsx
import React from "react"; const Category = function Category() { return <div>分类管理的内容</div>; }; export default Category;
-
React阶段/day0603_router6/src/views/Home.jsx 二级路由组件。
import React from "react"; import styled from "styled-components"; import { NavLink, Outlet } from "react-router-dom"; /* 组件样式 */ const HomeStyle = styled.div` padding: 10px; .nav-box { display: flex; border-bottom: 1px solid #eee; a { padding: 0 20px; line-height: 40px; font-size: 15px; color: #000; &.active { color: #1677ff; font-size: 16px; } } } `; const Home = function Home() { return ( <HomeStyle> <nav className="nav-box"> <NavLink to="/home/watch">数据监控</NavLink> <NavLink to="/home/worker">工作台</NavLink> <NavLink to="/home/message">消息中心</NavLink> </nav> {/* 首页的三级路由 */} <Outlet /> </HomeStyle> ); }; export default Home;
-
React阶段/day0603_router6/src/views/Login.jsx 二级路由组件。
import React from "react"; import { Form, Input, Checkbox, Button } from "antd"; import { UserOutlined, LockOutlined } from "@ant-design/icons"; import styled from "styled-components"; /* 组件的样式 */ const LoginStyle = styled.div` .remember { display: flex; justify-content: space-between; align-items: center; a { font-size: 14px; color: #1890ff; } } .submit { width: 100%; } `; const Login = function Login() { return ( <LoginStyle> <Form autoComplete="off" initialValues={{ account: "", password: "", }} > <Form.Item name="account"> <Input size="large" placeholder="请输入账号" prefix={<UserOutlined />} /> </Form.Item> <Form.Item name="password"> <Input.Password size="large" placeholder="请输入密码" prefix={<LockOutlined />} /> </Form.Item> <Form.Item> <div className="remember"> <Checkbox checked>记住账号密码</Checkbox> <a href="">忘记密码?</a> </div> </Form.Item> <Form.Item> <Button className="submit" type="primary" size="large"> 立即登录 </Button> </Form.Item> </Form> </LoginStyle> ); }; export default Login;
-
React阶段/day0603_router6/src/views/Personal.jsx
import React from "react"; const Personal = function Personal() { return <div>个人中心的内容</div>; }; export default Personal;
-
React阶段/day0603_router6/src/views/Register.jsx
import React from "react"; import { Form, Input, Button } from "antd"; import { LockOutlined, PhoneOutlined } from "@ant-design/icons"; import styled from "styled-components"; /* 组件的样式 */ const RegisterStyle = styled.div` .submit { width: 100%; } .code-box { display: flex; justify-content: space-between; align-items: center; .ant-form-item { &:nth-child(1) { margin-right: 10px; } } } `; const Register = function Register() { return ( <RegisterStyle> <Form autoComplete="off" initialValues={{ phone: "", code: "", }} > <Form.Item name="phone"> <Input size="large" placeholder="请输入手机号" prefix={<PhoneOutlined />} /> </Form.Item> <div className="code-box"> <Form.Item name="code"> <Input size="large" placeholder="请输入验证码" prefix={<LockOutlined />} /> </Form.Item> <Form.Item> <Button size="large">发送验证码</Button> </Form.Item> </div> <Form.Item> <Button className="submit" type="primary" size="large"> 立即注册 </Button> </Form.Item> </Form> </RegisterStyle> ); }; export default Register;
-
-
react路由V6版本-基础版构建步骤
-
在主视图文件里引入构建一级路由。
- 引入HashRouter, Routes, Route, Navigate等react-router-dom提供的组件。
- HashRouter用于把组件包起来。
- Routes用于设置路由信息组-把多条路由信息组合成一组以便只渲染一个路由视图。
- Route用于设置单条路由信息。
- Navigate用于与Route配合起来设置重定向。
- 引入路由需要用到的业务视图组件。
- 使用HashRouter, Routes, Route, Navigate等及业务视图组件来构建路由。
-
<HashRouter></HashRouter>
所有需要用到路由信息的,都要用这个组件包起来。 -
<Routes></Routes>
包裹一组路由信息。- 内部只能放
<Route>标签
,放其它标签会报错。 - 所有级别的
路由匹配规则
或路由表
都写在一起。
- 内部只能放
-
<Route/>
与<Route></Route>
用来设置一条路由信息。-
<Route></Route>
内部可以嵌套<Route/>
与<Route></Route>
。 -
默认匹配规则
类似于
精准匹配。 -
被嵌套的
<Route/>
标签就是子级路由。 -
子级路由可以省略父级路由地址。
- 不过子级路由以
/
开头,就会被认为是绝对路径。 - 子级路由不以
/
开头,那么其前方就会自动添加上父级路由的地址。
- 不过子级路由以
-
要渲染的组件用element属性来设置,但element属性的值必须是一个组件标签的格式,而不能只是一个函数变量。
<Route path="personal" element={<Personal />} />//一个组件标签的格式,是对的。
<Route path="personal" element={Personal} />//一个函数变量,是错的。
import React from "react"; // 1. 引入HashRouter, Routes, Route, Navigate等react-router-dom提供的组件。引入HashRouter用于把组件包起来,Routes用于设置路由信息组-把多条路由信息组合成一组以便只渲染一个路由视图,Route用于设置单条路由信息,Navigate用于与Route配合起来设置重定向。 import { HashRouter, Routes, Route, Navigate } from "react-router-dom"; // 2. 引入路由需要用到的业务视图组件。 import BasicLayout from "./layout/BasicLayout"; import UserLayout from "./layout/UserLayout"; import Error from "./layout/Error"; import Login from "./views/Login"; import Register from "./views/Register"; import Home from "./views/Home"; import Personal from "./views/Personal"; import Category from "./views/Category"; import Watch from "./views/home/Watch"; import Worker from "./views/home/Worker"; import Message from "./views/home/Message"; const App = function App() { // 3. 构建路由。 return ( <HashRouter> <Routes> <Route path="/" element={<BasicLayout />}> <Route path="" element={<Navigate to="/home" />} /> <Route path="home" element={<Home />}> <Route path="" element={<Navigate to="/home/watch" />} /> <Route path="watch" element={<Watch />} /> <Route path="worker" element={<Worker />} /> <Route path="message" element={<Message />} /> </Route> <Route path="category" element={<Category />} /> <Route path="personal" element={<Personal />} /> </Route> <Route path="/user" element={<UserLayout />}> <Route path="" element={<Navigate to="/user/login" />} /> <Route path="login" element={<Login />} /> <Route path="register" element={<Register />} /> </Route> <Route path="/404" element={<Error />} /> <Route path="*" element={<Navigate to="/404" />} /> </Routes> </HashRouter> ); }; export default App;
-
-
<Route path="*" element={<Navigate to="/404" />} />
用于设置路由跳转。
-
- 引入HashRouter, Routes, Route, Navigate等react-router-dom提供的组件。
-
在父级路由匹配组件的指定位置,基于
<Outlet/>组件
把子级路由匹配的内容进行渲染!// 1. 引入Outlet组件。 import { Outlet } from "react-router-dom" {/* 2. 在父级路由匹配组件的指定位置,基于`<Outlet/>组件`把子级路由匹配的内容进行渲染! */} <Outlet />
import { useState } from "react" import { Menu, Button } from "antd" import { HomeOutlined, ClusterOutlined, UserOutlined, MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons' import styled from "styled-components" import logo from "@/assets/images/logo.svg" import avatar from "@/assets/images/touxiang.png" // 1. 引入Outlet组件。 import { Outlet } from "react-router-dom" /* 组件样式 */ const BasicLayoutStyle = styled.div` height: 100%; overflow: hidden; .header{ box-sizing: border-box; padding: 0 15px; height: 48px; background: #001529; display: flex; justify-content: space-between; align-items: center; .logo, .info{ line-height: 48px; font-size: 18px; color: #FFF; display: flex; align-items: center; img{ margin-right: 10px; width: 35px; height: 35px; } } .info{ font-size: 14px; img{ width: 30px; height: 30px; } } } .content{ height: calc(100% - 48px); display: flex; .menu-box{ height: 100%; background: #001529; .ant-btn{ margin-left: 4px; background: transparent; box-shadow: none; } .ant-menu-item{ padding: 0 24px; } .ant-menu-inline-collapsed{ .ant-menu-item{ padding: 0 28px; } } } .view-box{ box-sizing: border-box; padding: 15px; height: 100%; flex-grow: 1; .component{ height: 100%; overflow-y: auto; overflow-x: hidden; background: #FFF; } } } ` const BasicLayout = function BasicLayout() { // 左侧Menu的数据 const menuItem = [{ key: 'home', label: '控制面板', icon: <HomeOutlined /> }, { key: 'category', label: '分类管理', icon: <ClusterOutlined /> }, { key: 'personal', label: '个人中心', icon: <UserOutlined /> }] // 定义状态 let [collapsed, setCollapsed] = useState(false) return <BasicLayoutStyle> <div className="header"> <h2 className="logo"> <img src={logo} alt="" /> Ant Design </h2> <div className="avatar"> <p className="info"> <img src={avatar} alt="" /> 海贼王-路飞 </p> </div> </div> <div className="content"> <div className="menu-box"> <Button type="primary" onClick={() => { setCollapsed(!collapsed) }}> {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} </Button> <Menu mode="inline" theme="dark" items={menuItem} defaultSelectedKeys={['home']} inlineCollapsed={collapsed} /> </div> <div className="view-box"> <div className="component"> {/* 主页的二级路由 */} {/* 2. 在父级路由匹配组件的指定位置,基于`<Outlet/>组件`把子级路由匹配的内容进行渲染! */} <Outlet /> </div> </div> </div> </BasicLayoutStyle> } export default BasicLayout
与路由V5版本的区别
react-router-dom(V6)
与react-router-dom(V5)
对比
-
都是基于
HashRouter()
与BrowserRouter()
来指定路由的模式,而且建议所有的组件都放在HashRouter()与BrowserRouter()这类Router
中。 -
V6版本中没有了
<Switch>
,因为不需要了,其内部自己做了类似于<Switch>
的处理。 -
V6中没有了
<Redirect>
,但是可以基于<Navigate to="/404"/>
来代替它。- 在V5版本中,
<Redirect />
相当于特殊的<Route/>
,我们是基于它设置重定向的规则的。<Redirect from="*" to="/404" />
- 在V6版本中,
<Navigate/>
是一个组件,渲染这个组件时会重定向到该组件的to属性指定的地址
。<Route path="*" element={<Navigate to="/404" />} />
- 在V5版本中,
-
V6中也是基于
<Route/>
设置匹配规则,只不过都需要放在<Routes></Routes
>中,而且在<Route/>
上设置的详细规则,和V5版本有很大的区别:- 无需在
<Route/>
上设置exact属性
用于进行精准匹配
了,因为默认都是类似于精准匹配
。 <Route/>
上path属性
和之前一样,设置对应的匹配地址。- 匹配成功后需要
渲染那个组件
不再基于<Route/>
上component属性
处理,而是基于<Route/>
上element属性
渲染,而且也没有了<Route/>
上render函数属性
这样的配置,element
渲染的内容需要写成<Component/>
这种格式!-
<Routes></Routes>
只能放<Route/>
。 -
V5旧:
import { HashRouter, BrowserRouter, Route, Switch, Redirect } from 'react-router-dom' import BasicLayout from "./layout/BasicLayout" import UserLayout from "./layout/UserLayout" import Error from "./layout/Error" <HashRouter> <Switch> <Route path="/user" component={UserLayout} /> <Route path="/404" component={Error} /> <Route path="/" component={BasicLayout} /> <Redirect to="/404" /> </Switch> </HashRouter> //或 <HashRouter> <Route path="/user" component={UserLayout} /> </HashRouter>
-
V6新:
import { HashRouter, Routes, Route, Navigate } from "react-router-dom"; import BasicLayout from "./layout/BasicLayout"; import UserLayout from "./layout/UserLayout"; import Error from "./layout/Error"; <HashRouter> <Routes> <Route path="/" element={<BasicLayout />}></Route> <Route path="/user" element={<UserLayout />}></Route> <Route path="/404" element={<Error />} /> <Route path="*" element={<Navigate to="/404" />} /> </Routes> </HashRouter> //或 <HashRouter> <Routes> <Route path="/" element={<BasicLayout />}></Route> </Routes> </HashRouter>
-
- 无需在
-
V6有一个重大的变革:所有级别的
路由匹配规则
或路由表
都写在一起,而不再像V5一样,需要分散到指定组件的特定位置
上,这样有利于路由的统一管理
!<Route path="/user" element={<UserLayout />}> /* - 在`子级路由中`其path可以省略`父级路由的地址` - 但是也不要自己再加`/` - `path=""` 等价于 `path="/user"` - `path="login"`等价于 `path="/user/login"` - 如果路由地址是`/user/xxx`,首先和一级路由`/user`进行匹配了,渲染`UserLayout组件`后,进入`/user`的`子级路由`进行匹配; - 在`子级路由`中`一项项地进行匹配`,匹配成功,就把`子级路由`中`element属性指定的组件`,放在`UserLayout组件`中的`<Outlet>容器`中进行渲染! - 如果在`子级路由`中没有任何匹配的,则跳出这一级,继续向下匹配`与/user路由同级`的`其它的一级路由`! */ <Route path="" element={<Navigate to="/user/login" />} /> <Route path="login" element={<Login />} /> <Route path="register" element={<Register />} /> </Route>
-
在
子级路由中
其path可以省略父级路由的地址
。- 但是也不要自己再加
/
。 path=""
等价于path="/user"
。path="login"
等价于path="/user/login"
。
- 但是也不要自己再加
-
如果路由地址是
/user/xxx
,首先和一级路由/user
进行匹配了,渲染UserLayout组件
后,进入/user
的子级路由
进行匹配;- 在
子级路由
中一项项地进行匹配
,匹配成功,就把子级路由
中element属性指定的组件
,放在UserLayout组件
中的<Outlet>容器
中进行渲染! - 如果在
子级路由
中没有任何匹配的,则跳出这一级,继续向下匹配与/user路由同级
的其它的一级路由
!
- 在
-
但是需要在上级路由匹配组件的指定位置,基于
<Outlet/>
把下级路由匹配的内容进行渲染!
-