目录
1、react-router@5
1-1、在项目中安装路由
1-2、一个项目使用一个路由器来管理路由即可
1-3、 路由组件和一般组件的区别
1-6、使用 Switch 标签
1-7、BrowserRouter解决多级路径匹配样式丢失问题
1-8、路由的模糊匹配和严格匹配
1-9、路由重定向 Redirect
1-10、嵌套路由(多级路由)
1-11、向路由组件传递参数
1)params: 传递参数:
2)search(query): 传递参数:
3)state (不同于组件身上的 state)
1-12、使用 replace 模式
1-13、使用编程式路由导航
1-14、在一般组件中使用编程式路由导航
1-15、BrowserRouter 和 HashRouter 对比
2、react-router@6
2-1、6版本中移除了先前的,引入了新的替代者
2-3、useRoutes 使用路由表
2-4、 Outlet 组件标签
2-5、路由 params 参数
2-6、search 参数
2-7、使用state参数
2-8、编程式路由导航
2-10、useResolvePath() 解析路径
2-11、懒加载
2-12、react.createContext 祖组件向后代组件传递内容
这里使用旧版本5:
npm i react-router-dom@5
新版本是@6
在 index.jx 文件中,渲染App时,用 指定的路由器包裹 App 组件
使用 BrowerRouter 或 HashRouter
import {BrowserRouter} from 'react-router-dom';
......
root.render(
);
1)写法不同:
一般组件:
路由组件:
2)存放位置最好区分开
一般组件:component
路由组件:pages routeComponent
3)接收到的参数不同:
一般组件:接收到的参数是在组件标签中所传的参数
路由组件:接收到三个固定的属性history、location、match
Link 和 NavLink 都是内置组件 ,相当于原生HTML中的a标签,点击这两个元素后,都会跳转到指定的路由页面。
当 Link 标签处于激活状态时,如果需要给该 Link 动态添加一个CSS类(非激活状态时该类移除)时,可以使用 NavLink 标签替代 Link 标签。
NavLink 默认添加的类名为 active,如果需要自己指定一个类名,使用属性activeClassName = "customActiveClassName"
Home
当需要使用多个 NavLink,且多个 NavLink 有相同的属性和值(如有共同标签属性activeClassName='act-link')时。
如果有多个参数传递给 MyNavLink,可以在 MyNavLink 中使用 {...this.props} 来展开
指定 MyNavLink 的 innerText:
1)使用指定的children标签属性:
2)传统非闭合标签方式:
在路由区域块中,如果不使用 Switch 将注册路由包裹,那路由在匹配到对应的注册路由后,仍然会向后继续匹配,
最后会将匹配到的所有组件都展示到路由区域。
使用Switch将注册路由都包裹起来,那么路由匹配到第一个注册路由后就会停止往后匹配。switch 也可以简单理解为路由组件的展示区域。
context | test
}/>
1)public/index.js 中引入样式 ./xxx 写成 /xxx
2)public/index.js 中引入样式 ./xxx 写成 %PUBLIC_URL%/xxx (React中适用)
3)使用 HashRouter
let NavLinkToArr = NavLink.to.split('/')
let RoutePathArr = Route.path.split('/')
1) 模糊匹配
模糊匹配是默认开启的
NavLinkToArr 和 RoutePathArr 两个数组依次对应匹配,RoutePathArr 被完全匹配后,便应用该注册路由,而不论 NavLinkToArr 中是否还有剩余的元素(即 NavLinkToArr.length >= RoutePathArr)
2) 严格匹配:
开启严格匹配(exact 属性为 true 时):
需要NavLinkToArr 和 RoutePathArr 两数组长度相等,且元素值一一对应时,才应用该注册路由。
严格匹配需要时再开启,有时会导致无法匹配到二级路由。
写在所有注册路由的后面,当前面的注册路由都匹配不到时,就匹配到重定向的注册路由
不使用 Switch 包裹注册路由时,如果匹配到注册路由了,会继续往下匹配其他路由,包括在最后面的 Redirect,最后会应用 Redirect 所指定的路由页面 。
1) 注册子路由时,path上要带上父路由组件的path
如 News 和 Message 是 Home 的子组件 在Home.jex中:
this is Home Page
to message
to news
2)路由的匹配每次都是重头开始的,按注册的顺序进行匹配的。
detail
or:
detail
声明接收参数:
在路由组件中拿到传递过来的参数:
this.props.match.params.id
如果没有声明接收参数,即
虽然可以模糊匹配到该路由组件,但是参数会丢失。
detail
不需要声明接收:
在路由组件中获取到 search 参数:
2-1)需要引入一个React配套已经安装好的库——querystring 直接引入即可:
import qs from 'querystring';
2-2)qs 的基本使用:
// 将 urlencode 解析成对象:
let res = qs.parse(urlencode);
// 将 对象转换成 urlencode 字符串:
let obj = qs.stringify(obj);
2-3)获取到 search 参数:
this.props.location.search;
获取到的是 urlencode 类型的字符串,如:?id=3&content=你好
然后使用 qs 进行解析,就可以使用。
state 参数与上述两种类型不同,state类型参数不会展示到 URL 地址栏中;
传递参数:
detail
不需要声明接收:
在路由组件中使用 state 参数:
this.props.location.state.id
this.props.location.state.content
需要注意的是,当在有history,即有浏览器历史缓存的时候,刷新页面在访问该地址,是有数据的。但如果用户清除了缓存数据,那么直接访问该地址,就不会有数据。
默认使用的是 push。
使用 replace:
detail
or:
detail
关键是使用路由组件的 props 上的 history 中的函数:
this.props.history.go(n) —— 往前或往后 n 个单位
.goBack() —— 回退一个页面
.forword() —— 前进一个页面
.push(path, state) —— 将新页面压入栈顶(跳转到一个新的页面,可以回退到当前的页面)
.replace(path, state) —— 将新页面替换掉当前页面(跳转到一个新的页面,不可回退到当前页面)
借助 react-router-dom 中的 withRouter 函数:
import withRouter from 'react-router-dom'
在 Message 组件中先使用 this.props.history. 或其他路由组件中的属性(location、match)
创建完类式组件后,再使用默认导出:
export default withRouter(Message);
导出经 withRouter 加工后的组件。Message 组件经过 withRouter 加工后,this.props 中将具有路由组件所具有的几个属性:
history、location、match
1、底层原理不同:
BrowserRouter 使用的是 H5 中的history API,对 IE9 以下版本不兼容
HashRouter 使用的是URL的哈希值
2、path表现形式不同
体现在 HashRouter 的路径中以 /#/ 开头,而 BrowserRouter 正常
3、对于路由传递state类型参数的影响
BrowserRouter 因为依靠浏览器历史对象,直接刷新不会有影响,state参数在浏览器缓存中
而 HashRouter 刷新页面 state 参数会丢失
4、HashRouter 可以解决多级路径时,样式丢失的问题
当URL发生变化时,Routes会查找全部的Route,以找到最佳的组件。
只要
可以用来重定向
}/>
{\* element即组件 *\}
{\* replace表示跳转的方式 *\}
使用路由表之后就不用写 Routes 包裹 n 个 Route了,使用Outlet来占位表示路由组件的展示区域
路由表的规则可以放到src的routes文件夹下的index.jx
import Home from './pages/Home'
import About from './pages/About'
import {Navigate} from 'react-router-dom'
import Child from './pages/Child'
export default [
{
path:'/home',
element: ,
children:[
{
path:'child',
element:
}
]
},{
path:'/About',
element:
},{
path:'/',
element:
}
]
在 App.jsx 中引入该路由表
import useRoutes from 'react-router-dom'
import routes from './routes/index.js'
// 根据路由表生成相应的路由规则
const element = useRoutes(routes);
{/* 注册路由 */}
{element}
用来指定路由页面呈现的位置
在路由规则(路由表)中要占位:
// 路由表中
{
path:'/home/:id/:name',
component:
}
Link 组件的 to 要改写。
在接收的时候要使用 useParams
import {useParams} from 'react-router-dom'
const {id,title,content} = useParams();
还有 useMatch 也可以拿到,同时也能收集到history、location等内容
不需要改变路由规则。
传递的时候:
接收的时候需要使用到 useSearchParams
import {useSearchParams} from 'react-router-dom'
// 这是对数组的解构,第一个元素赋给searchParams,是我们需要的search数据
// 第二个setSearchParams是用来修改search参数的
const [searchParams, setSearchParams] = useSearchParams();
// 获取到search参数 要使用get方法
const id = searchParams.get('id');
const name = searchParams.get('name');
// 使用第二个参数可以修改search参数,location也会跟着一起改变
setSearchParams('id=001&name=张三');
// 需要引入 useLocation
import {useLocation} from 'react-router-dom'
const {state:{id,name}} = useLocation();
使用 useNavigate 这个API
import {useNavigate} from 'react-router-dom'
const navigate = useNavigate();
// navigate('/home',{
// replace:false,
// state:{
// id:m.id,
// name:m.name
// }
// })
navigate('detail',{
replace:false,
state:{
id:m.id,
name:m.name
}
})
使用编程式路由导航只能传递 state 参数。
非路由组件(一般组件)也可以使用。
返回值有三:POP、PUSH、REPLACE
pop表示是直接进入到当前页面或是刷新页面的结果
参数接收一个字符串,会返回 search、path、hash 等内容
useResolvePath('/about#que?name=zhangsan&age=13')
懒加载组件一般是路由组件
import {lazy, Suspense} from 'react'; // lazy是一个函数,Suspense是一个组件
import Loading from './Loading'; // 引入显示正在加载的展示组件
const Home = lazy(()=> import('./Home')); // 懒加载组件的引入方式
const About = lazy(()=> import('./About'));
// 需要用Suspense包裹懒加载组件 当还在处理懒加载组件时,会先渲染Loading组件到页面指定位置
}>
// 1) 创建Context容器对象在祖组件和后代组件都看得见的地方创建:
const XxxContext = React .createContext()
// 2) 染子组时,外面包xxxContextProvider,通过vaue属性给后代组件传递数据
子组件
// 3后代组件读取数据:
//第一种方式:仅适用于类组件
static contextType = xxxContext // 声明接收context
this.context // 读取context中的value数据
//第二种方式: 函数组件与类组件都可以
{
value => ()=>{ // value就是context中的value数据要显示的内容
{/* 要显示的内容 */}
}
}