第5章:React路由

5.1. 相关理解

5.1.1. SPA的理解

什么是SPA?

就是一个项目里面只有一个html文件,无论是vue还是react项目,都是只有public文件夹里面的一个Index.html文件。为什么可以这样做,就能够有丰富的交互功能,页面跳转什么的都可以实现?因为有了路由技术。

在没有路由技术之前,跳转需要使用a标签来进行跳转,a标签的href指向的是不同的html文件,那么跳转到相应的html时会刷新页面来更新渲染的内容。这是路由技术实现之前的解决办法。

前端路由技术有两种实现方式:hash和history。参考:https://zhuanlan.zhihu.com/p/61694291,这篇文章将前端路由和后端路由讲解的很清楚,有时间一定要重点看一下,前后端的路由问题搞清楚了,那么MVVM、MVC、MTV模型都可以搞清楚了,https://zhuanlan.zhihu.com/p/426782949。我记得我刚开始学习flask和Django的时候,就是路由没有搞清楚,所以一直学习的很艰难,甚至现在学习Nodejs的时候,也是路由没有搞清楚,所以搭建http服务一直不理解,不理解就学习不下去,所以一定要先将后端路由搞清楚了,再来学习Nodejs。甚至我感觉搞清楚了之后,Java我都不想学习了,因为我想学Java的全部原因只是为了搭建服务端,而Java实在太庞大,投入产出比会非常小,不如把已有的前端、nodejs、Python真正搞定,真的就没有必要学习Java了。

 

hash路由原理:

HTML页面中通过锚点定位原理可进行无刷新跳转,触发后url地址中会多出# + 'XXX'的部分,同时在全局的window对象上触发hashChange事件,这样在页面锚点哈希改变为某个预设值的时候,通过代码触发对应的页面DOM改变,就可以实现基本的路由。

下面用a标签的#写法讲解一下“锚点定位”是什么样子的,注意:只是说明锚点的运行方式,至于hash路由是不是这种方式实现的,我不知道。

运行效果,注意看url栏的变化:

mdn的一些概念:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a

image-20230811215800089

 

history路由原理:

HTML5History API(就是BOM的history API)为浏览器的全局history对象增加的扩展方法。一般用来解决ajax请求无法通过回退按钮回到请求前状态的问题

  1. 单页Web应用(single page web application,SPA)。
  2. 整个应用只有一个完整的页面。页面里面会区分为导航区,展示区(展示组件)、标题栏等等区域。那么点击导航区就可以切换显示不同的组件,就要用到路由的技术。
  3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。
  4. 数据都需要通过ajax请求获取, 并在前端异步展现。

5.1.2. 路由的理解

简单理解的路由工作原理:路由模块里面监测URL里面的路径path的变化,比如说从localhost:5000变为了localhost:5000/home,那么路由模块里面的前端路由器会根据映射关系 key:value 来展示相应的组件。

/react全家桶资料/06其他/前端路由的基石history.html 中,老师引入了一个名称为history.js的第三方库,注意:这个history.js里面的createBrowserHistory()方法只是对BOM的history api的一个封装,本质上还是使用的BOM的history api。还有一个createHashHistory()方法,是对hash路由的实现。在里面可以看到,路由的实现其实很简单。

1. 什么是路由?

  1. 一个路由就是一个映射关系(key:value)
  2. key为路径, value可能是function(主要指后端路由,但是后端路由同样可以返回html)或component(主要指前端路由)

2. 路由分类

  1. 后端路由:

    1)理解: value是function, 用来处理客户端提交的请求。

    2)注册路由:router.get(path, function(req, res))

    3)工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据

这里以老师提供的server.js举例说明:

image-20230810222503634

  1. 前端路由:

1)浏览器端路由,value是component,用于展示页面内容。

2)注册路由: <Route path="/test" component={Test}>

3)工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件

5.1.3. react-router-dom的理解

为什么学习的是react-router-dom,而不是react-router呢?因为react-router有三种实现:1、web端,2、react-native端,3、anywhere端(任意哪一个端)。

现在主要就是学习web端,也就是react-router-dom这个库。

为什么不学习anywhere端的实现呢?因为没有必要,大而全反而不知道怎么用,要学就学针对性最强的端。

image-20230811215650171

Route和Router的区别?

Route翻译为“路由”,Router翻译为“路由器”。这里只讲react中二者的区别,vue中可能有一些不同。

Route 是用于声明路由映射到应用程序的组件层。

Router我们可以把它看做是react路由的一个路由外层盒子,它里面的内容就是我们单页面应用的路由以及路由组件

  1. react的一个插件库。
  2. 专门用来实现一个SPA应用。
  3. 基于react的项目基本都会用到此库。

5.2. react-router-dom相关API

5.2.1. 内置组件

  1. <BrowserRouter>
  2. <HashRouter>
  3. <Route>
  4. <Redirect>
  5. <Link>
  6. <NavLink>
  7. <Switch>

5.2.2. 其它

  1. history对象
  2. match对象
  3. withRouter函数

5.3. 基本路由使用

5.3.1这里用一个案例来引出react-router-dom的使用:

1、安装:npm install react-router-dom@5,提示:老师讲解的时候,是版本5,所以需要这么安装。在后面讲解了版本6,到时候有一些用法会不同,都有笔记的。

2、使用react-router-dom的一个套路:拿到一个需求,1、看哪是导航区,哪是展示区(主要区分这两个区域,因为这里暂时把别的区域看成是固定的了,当然顶部栏也可能根据导航区的变化而变化,那么顶部栏同样可以看成是另一个展示区);2、导航区对应的展示组件就可以先创建出来,里面放静态的页面;3、由于是SPA项目,以这个案例来说明,其实顶部的标题栏、左侧的导航栏、左下侧的展示区都是在app.jsx中的,更精准的说应该都在index.html中,所以导航链接组件和展示区的组件是在同一个文件中的。(这一点和vue是完全不同的,概念要区分清楚,vue里面的路由其实都定义在router/index.js中,由api来自动区分,写法也完全不同。其实react的这种用法更加直观、更好理解。我知道这里我还没有说清楚,如果感到难以理解,就多看几遍视频,这一点必须理解,非常重要

3、先写静态页面,可以参考 /react全家桶资料/04_静态页面/route_page1 里面的代码,about.html和home.html的差别是什么?你仔细看一下,1、a标签的active状态在哪个上面,哪个标签就高亮,URL栏里面的path显示哪个地址,右侧的展示区就展示对应的组件;2、展示区的内容不一样,那么需要展示的组件就放在这里(这种写法要理解清楚,可能刚开始不是那么容易从vue写法转过来的) 。那么就把about.html里面的代码粘贴到app.jsx,css文件放到public里面里面,并引入。

4、编写展示组件的内容。这里的例子非常简单,但其实组件里面的内容可以非常复杂,还可以是路由的嵌套,后面都会讲的。

5、在App.jsx中引入路由的各种方法和组件(案例中主要是引入了<Route><Link><BrowserRouter>组件)。

①编写路由链接:

启动npm start,看一下效果:

image-20230812075527783

报错了,提示必须在<Router>组件里面使用<Link>组件,这个报错其实不是很精细准确,错误提示里面的<Router>其实不能直接使用,react-router-dom提供了两种router组件,<BrowserRouter><HashRouter>,这里使用<BrowserRouter>

显示效果:

可以看到,点击路由链接的时候,path路径发生了变化。但是展示区没有变化,那么下一步就是编写展示区。

②编写展示区:

看一下效果:

image-20230812081932977

报错了,提示<Route>组件必须写在<Router>里面,改造一下:

看一下效果,不报错了,但是点击路由链接,展示区是没有变化的。

原因是什么呢?原因是整个应用要用一个路由器来管理,如果有多套<BrowserRouter></BrowserRouter>,那么多套之间是没有数据沟通的。所以需要在项目的index.js用<BrowserRouter></BrowserRouter>包裹app组件。

查看效果:

已经实现基本的功能了。

react-router的官方examples:https://github.com/remix-run/react-router/tree/dev/examples,可以参考里面的写法。

提示:

在react脚手架项目中,使用 ctrl+/ 可以在jsx中快速注释代码。那为什么之前练习时没有这种效果呢?是因为react脚手架帮我们实现了这个功能。

5.3.2 路由组件和一般组件

区别一:一般组件的使用:<Home />,路由组件的使用<Route path="/home" component={Home} />

区别二:工程化的规定,路由组件放在pages文件夹里面,一般组件放在components文件夹里面。

区别三:一般组件如果不给它传值的话,它的this.props{},写组件时传递了什么,就接收到什么。但是路由组件不给它传值的话,它的this.props{history:{xxx},location:{xxxxx},match:{xxxx},staticContext:{xxxx}},路由组件就可以用这些值来处理相应的事情。

5.3.3 案例优化-添加路由链接高亮

将Link组件换为NavLink组件就可以了。

为什么呢?a标签的案例中,是使用active这个类名来实现的高亮效果,为什么NavLink里面没有加任何类名,就实现了高亮效果呢?因为NavLink里面的一个属性activeClassName的默认值就是active,这只是一种巧合而已。

那么如果想换高亮的样式,那么就要显式的指定高亮的类名。样式可能有权重问题,调整一下就行了。

5.3.4 NavLink的封装

在使用<NavLink></NavLink>的时候,里面有很多固定的属性,那么就可以封装一个NavLink组件,只把不同的属性传过去就行了。标签属性好传值,但是<MyNavLink to="/home">Home</MyNavLink>,里面的这个标题Home,怎么传递过去呢?当然可以这样做:<MyNavLink to="/home" title="Home"></MyNavLink>,用this.props接收就行了,但是这样不是最佳方案。

<MyNavLink to="/home">Home</MyNavLink>这里的Home叫做标签体内容,我们输出一下,看this.props接受到没有。

image-20230812111945788

注意:这里输出了两次,还不知道具体原因是什么,等做项目的时候再看吧。

可以看到标签体也是一个特殊的标签属性,那么怎么接收呢?可以用this.props.children来接收。但是既然它是一个标签属性,那么直接写在标签里面行不行呢?是可以的。

5.3.5 Switch的使用

通常情况下,<Route />里面的path和component是一一对应的关系,但是有时候代码写错了或者特殊要求,写成这样了:

那么路由在匹配时,会将两个都匹配上,都展示出来。那么就要用到<Switch></Switch>组件。

Switch可以提高路由匹配效率(单一匹配,一旦匹配到就不再进行匹配操作。即使代码写的不像上面的错误代码那样,也应该使用Switch组件,因为如果路由很多的话,使用Switch一旦匹配到,就不会去找别的组件,提高了效率)。

5.3.6 解决样式丢失问题

有一个需求,就是路由跳转的时候,path的地址要带上公司名称等等,写成这样<NavLink to="/atguigu/home" >Home</NavLink>,但这不是二级路由,只是规定了要带上/atguigu,会造成在刷新浏览器的时候,样式丢失。

原因是什么呢?原因是public/index.html引入CSS文件时,写成了这样:<link rel="stylesheet" href="./css/bootstrap.css" />,使用了相对路径。那么路由跳转的时候,路由地址是这样的http://localhost:3000/atguigu/home,点击浏览器刷新,webpack的devServer找资源实际上的处理是这样的:http://localhost:3000/atguigu/css/bootstrap.css,肯定找不到这个文件啊,找不到就默认返回public/index.html,所以没有样式。

为什么刚开始样式没有问题呢?因为刚开始的时候路由地址是这样的http://localhost:3000,肯定可以找到css文件。

解决办法有三种:

方法1:将引入css的路径写成绝对路径

方法2:在引入css时,使用%PUBLIC_URL%

方法3:使用HashRouter,一般不推荐这种方法,因为大厂讲究美观,路由也要美观。

5.3.7 路由的模糊匹配与严格匹配

1、<Route />默认使用的是模糊匹配,也就是“输入的路径”(<NavLink to="/home/a/b">Home</NavLink>)必须要包含“匹配的路径”(<Route to="/home" component={Home} />),且顺序要一致。

那此时匹配到了Home组件,但是输入的路径,后面的/a/b肯定是有用的啊,像在vue中就是匹配具体的页面了。在react中应该怎么处理呢?

Home组件里面肯定有子路由的,子路由的to属性就是具体的路径了,在下面的“嵌套路由”课程中可以看到。

比如说,如果“输入的路径”为to="/a/home/b",那么顺序不一致,也是匹配不了的。

2、开启严格匹配:<Route exact={true} path="/home" component={Home} />,可以简写为:<Route exact path="/home" component={Home} />。“严格匹配”就是指“输入的路径”全等于“匹配的路径”。

3、严格匹配不要随便开启,有需要再开,有时候开启会导致无法继续匹配二级路由。

5.3.8 Redirect(重定向)的使用

需求:页面一打开,默认选中一个路由,右侧展示相应的组件。不要是空白的页面。

这时候就要用到<Redirect />组件了,一般写在所有注册路由的下方,当所有路由都无法匹配时,跳转到<Redirect />指定的路由。

可以看到,输入的地址是http://localhost:3000,立即跳转到http://localhost:3000/about了。

为什么能行呢?你想一想,我访问时输入的是http://localhost:3000这个地址,路由监测到的path是"",与任何注册路由都匹配不了,那么就找到<Redirect />,跳转到它指定的路由。

 

5.4. 嵌套路由使用

效果

分析一下:

1、Home组件内容里面嵌套了一个“导航区+展示区”,那么只需要在Home组件里面进行相应的修改即可,里面创建两个组件News和Message,点击导航区就展示相应的组件。

image-20230812155947345

2、编写静态页面

/react全家桶资料/04_静态页面/route_page2 中可以看到编写好的Home部分的代码,将这部分代码先粘贴到Home/index.jsx里面。

3、编写路由组件的静态页面,将News和Message组件的静态页面编写好。

4、在Home组件中编写路由链接,注册路由。

看一下效果:

可以看到,点击Home里面的导航栏,路由跳转到/about了。为什么呢?

因为路由的匹配是有顺序的,路由首先匹配最外层的/about 和 /home,然后匹配Home里面的 /news 和 /message,当点击news或message时,路由还是先从最外层开始匹配,/about和/home都没有匹配上,那么就会执行<Redirect />里面的代码,于是就跳转到了 /about 了。

解决办法:

需要在编写路由链接和注册组件时,path加上父级的path(这里就涉及到了模糊匹配的知识了)。

显示效果:

可以看到,Home里面的导航栏和组件都是正常的,但是设置的News默认高亮没有效果,<Redirect to="/home/news" />没有效果。暂时还不知道原因,也搜索不到答案。

知道是什么原因吗???原来我把<Route />里面的path属性写成了to属性,路由当然匹配不到了。改成这样就OK了。

5.5. 向路由组件传递参数数据

效果

分析一下:

1、Message组件里面嵌套了一个“导航区+展示区”,那么只需要在Message组件里面进行相应的修改即可,里面创建Detail组件,点击导航区就展示相应的组件。

image-20230812182410144

2、编写静态页面。把导航区和展示区分出来。

3、编写路由组件的静态页面。静态页面就是ul和li,自己写一下。这个案例有一点不同,就是需要根据不同的message返回不同的详情信息,怎么办?就需要传递路由参数过来,根据这个参数做不同的处理。

怎么接收这个参数呢?在5.3.2讲解一般组件和路由组件的区别时,已经说明了,路由组件的this.props携带有参数,可以用这里面的参数。

4、编写路由链接,注册路由。既然需求是不同的message展示不同的详情,那么在跳转到详情界面时,就要传递路由参数过去,怎么传递呢?

这里以传递params参数作说明,套路是固定的,按套路来写就行了:

看一下效果:

5.5.1 向路由组件传递params参数

1、路由链接(携带参数)

携带的其实是“value”。

2、注册路由(声明接收)

声明接收的其实是“key”。

3、接收参数

在接收的时候,是从一个对象接收的,通过上面的方式已经定义好了。

const {id,name} = this.props.match.params

5.5.2 向路由组件传递search参数

传递参数:

接收参数:

看一下效果:

image-20230812193823985

原因:querystring原本是Node.js自带的库,再新版本中已被弃用,在名称上有所调整,功能基本没有太大变化,解决方案如下。

import qs from "qs"

看一下效果:

1、路由链接(携带参数)

2、注册路由(无需声明接收,正常注册即可)

3、接收参数

5.5.3 向路由组件传递state参数

注意:这个state参数是路由组件上to属性里面的state参数,不要和组件上的state状态搞混了。

1、路由链接(携带参数)

2、注册路由(无需声明接收,正常注册即可)

3、接收参数

5.5.4 小结

1、三种传参方式,在浏览器刷新后都可以保留住状态。(这是在BrowserRouter情况下说的,BrowserRouter实际上使用的是浏览器的history api,浏览器会保留住状态。但是HashRouter在刷新后会导致state参数丢失。)

2、三种传参方式的使用都很多,都要掌握,如果非要分一下,那么params传参可能是用的最多的。

5.6. 多种路由跳转方式

效果

5.6.1 push和replace

浏览器历史记录(路由记录)实际上是栈结构,push操作是将路由链接压栈;replace操作是替换掉目前的路由链接,也就是栈顶元素。

在编写路由链接的时候,如果不指定路由跳转方式,那么就默认是push方式。如何开启replace模式呢?需要添加replace属性。

5.6.2 编程式路由导航

需求:

1、案例中,展示news组件之后,2秒后自动切换到Message组件。

2、在Message的li后面加上两个按钮,一个通过push查看详情,一个通过replace查看详情。

3、下方添加“返回”和“前进”按钮,replace查看详情时是什么效果,push查看详情时是什么效果,自己看一下。

 

显示效果:

主要用到了this.props.history属性上的go,goForward,goBack,push,replace这5个api。

5.6.3 withRouter()的使用

需求:

想把上一个案例中的“回退”和“前进”按钮放到Header组件里面,就是“React Router Demo”这里面,要求可以操作路由的回退和前进。

分析一下:

Header组件是一般组件,不是路由组件,所以this.props上是没有history属性的,那就没有history的api来操作路由了,怎么办?

解决办法:

react-router-dom有一个withRouter方法,方法的作用:接受一个一般组件,让一般组件具备路由组件所特有的api,然后返回一个新组件。

显示效果:

5.6.4 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可以用于解决一些路径错误相关的问题。(eg:样式丢失的问题)

第6章:React UI组件库

6.1.流行的开源React UI组件库

6.1.1. material-ui(国外)

  1. 官网: http://www.material-ui.com/#/
  2. github: https://github.com/callemall/material-ui

6.1.2. ant-design(国内蚂蚁金服)

  1. 官网: https://ant.design/index-cn
  2. Github: https://github.com/ant-design/ant-design/

6.2 antd的基本使用

安装:npm install antd

6.3 antd样式的按需引入

任何与antd用法相关的问题,首先查找文档,查找不到再去搜索。

官网地址:

https://ant-design.gitee.io/docs/react/use-with-create-react-app-cn

提示:

有些问题可能在最新版本的文档中找不到答案,这一点我在使用vant文档时也发现了。可以切换文档的版本,看一下有没有答案。

下面的方式是按照antd@3.x版本来做的,现在都antd@5.8.3了,这种方法能不能使用,还需要在真正使用的时候去搜索一下。

当然,如果最新版本的UI库一些问题就是没有办法解决,那就降低版本看能不能使用,这些都是技巧啊。

image-20230813095035405

image-20230813095123687

6.4 antd自定义主题

image-20230813095237818

 

 

 

第9章:React Router 6 快速上手

1.概述

  1. React Router 以三个不同的包发布到 npm 上,它们分别为:

    1. react-router: 路由的核心库,提供了很多的:组件、钩子。
    2. react-router-dom: 包含react-router所有内容,并添加一些专门用于 DOM 的组件,例如 <BrowserRouter>
    3. react-router-native: 包括react-router所有内容,并添加一些专门用于ReactNative的API,例如:<NativeRouter>等。
  2. 与React Router 5.x 版本相比,改变了什么?

    1. 内置组件的变化:移除<Switch/> ,新增 <Routes/>等。

    2. 语法的变化:component={About} 变为 element={<About/>}等。

    3. 新增多个hook:useParamsuseNavigateuseMatch等。

    4. 官方明确推荐函数式组件了!!!

      ......

以之前的路由案例为例,使用react-router6来重新做,顺便学习react-router6的用法。

1、先从 /react全家桶资料/04_静态页面/route_page1 和 route_page2 把静态页面拷贝过来。采用函数式组件来编写。

主要用到了 {element}useRoutes,定义routes,<Navigate />重定向,还有NavLink的指定样式,函数式组件props使用方法。

2、首先实现about和home的路由。

显示效果OK。

3、实现news和message的路由。

主要用到了<Outlet />,二级路由:children属性。

4、实现detail的路由并传递路由参数。

主要用到了三种传递路由参数的方法,params,search,state。二级路由:children属性,<Outlet />。接收三种参数的方法:useParams()useSearchParams()useLocation()

5、一般组件操作路由

主要用到了useNavigate()方法。

 


2.Component

1. <BrowserRouter>

  1. 说明:<BrowserRouter>用于包裹整个应用。

  2. 示例代码:

2. <HashRouter>

  1. 说明:作用与<BrowserRouter>一样,但<HashRouter>修改的是地址栏的hash值。
  2. 备注:6.x版本中<HashRouter><BrowserRouter> 的用法与 5.x 相同。

3. <Routes/> 与 <Route/>

  1. v6版本中移除了先前的<Switch>,引入了新的替代者:<Routes>

  2. <Routes><Route>要配合使用,且必须要用<Routes>包裹<Route>

  3. <Route> 相当于一个 if 语句,如果其路径与当前 URL 匹配,则呈现其对应的组件。

  4. <Route caseSensitive> ,caseSensitive属性用于指定:匹配时是否区分大小写(默认为 false)。

  5. 当URL发生变化时,<Routes>都会查看其所有子<Route> 元素以找到最佳匹配并呈现组件 。

  6. <Route> 也可以嵌套使用,且可配合useRoutes()配置 “路由表” ,但需要通过 <Outlet> 组件来渲染其子路由。

  7. 示例代码:

<Route path="/login" element={<Login />}></Route>

element里面写成了标签,此时能不能传递props参数呢?这样操作起来就非常方便了。先查一下文档,试一下。我问了一下chatgpt,答案是可以,以后可以在实际项目中试一下。

通过 react-router-dom@6element 传递 props 的方法是可行的,你可以直接传递 props 给组件。例如:

然后在 Login 组件中,可以直接通过 props 获取 someProp 的值:

在这个例子中,Login 组件会直接接收到 someProp 的值 someValue

4. <Link>

  1. 作用: 修改URL,且不发送网络请求(路由链接)。

  2. 注意: 外侧需要用<BrowserRouter><HashRouter>包裹。

  3. 示例代码:

5. <NavLink>

  1. 作用: 与<Link>组件类似,且可实现导航的“高亮”效果。

  2. 示例代码:

6. <Navigate>

  1. 作用:只要<Navigate>组件被渲染,就会修改路径,切换视图

  2. replace属性用于控制跳转模式(push 或 replace,默认是push)。

  3. 示例代码:

7. <Outlet>

  1. <Route>产生嵌套时,渲染其对应的后续子路由。

  2. 示例代码:

使用了useRoutes生成路由,并使用{element}的方式将路由放到App.jsx里面,并不表示路由的操作就全部完成了。{element}只能渲染出路由表里面的第一级路由,像login、register、main、error这些页面可以当作一级路由来写,真正的点击菜单然后切换路由页面,这些路由都应该放到main里面去,作为它的children,里面再进行嵌套。所以你看最开始的那个案例,在App.jsx里面使用了<MyNavLink />进行路由跳转,下面就写成了{element}。那么登录成功之后,就进入到main页面中去,里面点击菜单进行路由切换,要么使用hooks,要么定义Link标签,这部分不变,重点是组件的容器变为了<Outlet />

不要以为vue项目中我只是在router/index.js里面注册了路由及组件,整个路由系统就做好了,不是这样的。web的整体布局我要在子组件的地方做<router-view></router-view>,还要做菜单的路由跳转router.push()这些,只不过是因为PC端都在使用框架,所以这部分都封装好了,我没有做而已,不要想当然了。

3.Hooks

1. useRoutes()

  1. 作用:根据路由表,动态创建<Routes><Route>

  2. 示例代码:

2. useNavigate()

  1. 作用:返回一个函数用来实现编程式导航。

  2. 示例代码:

3、案例说明:

需求:在Header里面进行路由回退和前进的操作。

分析:Header属于一般组件,是没有办法操作路由的,在router5中,一般路由里面想要操作路由,需要用到withRouter()方法,用到this.props.history上面的go、goForward、goBack等方法。

那么在router6里面该怎么办呢?直接使用useNavigate()这个hook,它提供了方法来操作路由。

实现:

看一下效果:

这个效果看上去有点不对,因为展示了多个detail的链接,应该都保存了才对,怎么点击返回是直接返回news呢?

原因是我使用了state传递路由参数,使用params和search传递参数是正常的。有时间找一下原因吧。


说明:下面的useParams(),useSearchParams(),useLocation(),useMatch()都是与路由传参相关的hook,那么编写路由链接和注册路由有什么变化呢?

在编写路由链接时params和search写法不变,state写法变得更简单了。由于路由表配置的出现,注册路由有了一些变化。如果是直接写<Route />,可以说没有变化,如果你记不清楚了,勤快点,把react-router-dom@5看一下。下面的例子只是Message和Detail的部分,足以说明问题。

TODO:里面我搜索到的答案:

参考文档:https://blog.csdn.net/VX_WJ88950106/article/details/126330829

将重定向的path设置为"",就可以了。

但是这个方法有个严重问题:

路由返回时,返回到/home/news就无法返回了,一直卡在这里。

说明解决办法不是这个,还需要另外找办法。

看了一下文档,useRoutes()里面是这么说的:

image-20230814102107037

image-20230814102226933

就是这个属性了:

image-20230814102503953

进行改造:

重定向没有问题,但是还是不能返回/about,等有时间看一下官方examples里面有没有解决办法吧。

@@有一点我没有想到,如果这里设置了index:true,没有设置path,那<Link>里面的to属性应该怎么写呢???

可是react-router5<Redirect />是可以一直返回的啊。

下面的3、4、5、6中,就说明了各种路由的hook的使用方法。

3. useParams()

  1. 作用:返回当前匹配路由的params参数,类似于5.x中的match.params

  2. 示例代码:

4. useSearchParams()

  1. 作用:用于读取和修改当前位置的 URL 中的查询字符串。

  2. 返回一个包含两个值的数组,内容分别为:当前的search参数、更新search的函数。

  3. 示例代码:

5. useLocation()

  1. 作用:获取当前 location 信息,对标5.x中的路由组件的location属性。

  2. 示例代码:

6. useMatch()

  1. 作用:返回当前匹配信息,对标5.x中的路由组件的match属性。这个虽然可以使用,但是相对于useParams() 来说复杂一些,所以多使用useParams()。

  2. 示例代码:


下面的4个hook,了解一下即可,用的不多。

7. useInRouterContext()

作用:如果组件在 <Router> 的上下文中呈现,则 useInRouterContext 钩子返回 true,否则返回 false。

怎么理解?一般项目中如果用到router,那么都会用<BrowserRouter><HashRouter><App />给包裹住,里面的组件不分路由组件、一般组件,使用useInRouterContext()返回的都是true。

使用场景:比如说你写了一个第三方库,你要知道使用者是不是在路由里面使用的,就可以做相应的处理。

8. useNavigationType()

  1. 作用:返回当前的导航类型(用户是如何来到当前页面的)。
  2. 返回值:POPPUSHREPLACE
  3. 备注:POP是指在浏览器中直接打开了这个路由组件(刷新页面)。

9. useOutlet()

  1. 作用:用来呈现当前组件中渲染的嵌套路由。

  2. 示例代码:

10.useResolvedPath()

  1. 作用:给定一个 URL值,解析其中的:path、search、hash值。

4.小结

react-router里面并不是只有这么多写法,我看到的是别人使用createBrowserRouter来配置路由表,写项目时用一下。