router6.0
安装:
安装: npm i react-router-dom
使用
一级路由
import React from 'react';
import {
Route, Routes} from "react-router-dom";
import Film from "../views/film";
import Cinema from "../views/Cinema";
import Center from "../views/Center";
function MRouter(props) {
return (
<Routes>
{
/*Route一定要包裹在Routes组件内部*/}
<Route path="/film" element={
<Film />}></Route>
<Route path="/cinema" element={
<Cinema />}></Route>
<Route path="/center" element={
<Center />}></Route>
<Route path="/" element={
<Redirect to="/film"></Redirect>}></Route>
<Route path="*" element={
<NotFound></NotFound>}></Route>
</Routes>
);
}
export default MRouter;
之后将MRrouter挂在至App.js
app.js
import logo from './logo.svg';
import {
HashRouter} from 'react-router-dom'
//HashRouter: 哈希模式
//BrowserRouter:浏览器模式
import './App.css';
import MRouter from "./router";
function App() {
return (
<HashRouter>
<MRouter></MRouter>
</HashRouter>
);
}
export default App;
路由重定向
index表示: 不匹配其他子路由,只在父组件路由的时候显示该组件,用于嵌套路由。
解决当前嵌套路由有多个子路由但本身无法确认默认渲染哪个子路由的时候,可以增加index属性来制定默认路由,index路由和其他路由不同的地方 是它没有path属性,和父路由共享同一个路径
第一种方案:Navigate
import {
Navigate, NavLink, Route, Routes} from "react-router-dom";
{
/* 路由重定向*/}
{
/* *表示万能匹配,当以上路由都未匹配到时,才会走下面的匹配,渲染film组件*/}
<Route path="*" element={
<Navigate to="/film"></Navigate>}></Route>
第二种方案: 自定义redirect(useNavigate钩子函数)
```js
<Route path="*" element={<Redirect to="/film"></Redirect>}></Route>
// Redirect组件:
import React, {useEffect} from 'react';
import {useNavigate} from "react-router-dom";
function Redirect({to}) {
const navigate = useNavigate() //useNavigate: react-router-dom提供的钩子函数,返回一个对象
useEffect(() => {
navigate(to,{replace: true}) //replace表示关闭之前的页面
},[])
return null
}
export default Redirect;
嵌套路由
嵌套路由router.js部分写法:
<Route path="/film" element={
<Film />}>
{
/*index表示默认展示的子路由 与父路由展示同一路径*/}
<Route index element={
<Redirect to="/film/nowPlaying"></Redirect>} ></Route>
<Route path="/film/comingSoon" element={
<ComingSoon />}></Route>
{
/*相对路径写法: 相对于父路由的写法*/}
<Route path="nowPlaying" element={
<NowPlaying />}></Route>
<Route path="comingSoon" element={
<ComingSoon />}></Route>
</Route>
<Route path="/cinema" element={
<Cinema />}></Route>
<Route path="/center" element={
<Center />}></Route>
</Route>
在Film组件中要留好占位符:
import React from 'react';
import {
Outlet} from "react-router-dom";
function Film(props) {
return (
<div>
{
/*注意路径关系*/}
<div style={
{
height:'200px',background:'lightblue'}}>大轮播</div>
{
/*路由容器: 类似于view的router-view*/}
<Outlet></Outlet>
</div>
);
}
export default Film;
声明式导航和编程式导航
声明式导航:
编程式导航: location.href=“#”
声明式导航
import React from 'react';
import './tabbar.css'
import {
Link,NavLink} from "react-router-dom";
function TabBar(props) {
return (
<div>
<ul className="footer">
<li>
{
/*<Link to="/film"> 电影</Link>*/}
{
/*NavLink具有Link的一切功能,并且具有高亮显示的功能*/}
{
/*className是给NavLink的一个属性,支持传入回调函数*/}
<NavLink to="/film" className={
({
isActive}) =>
isActive ? 'tabbar_active' : ''
}> 电影</NavLink>
</li>
<li>
<Link to="/cinema"> 影院</Link>
</li>
<li>
<Link to="/center"> 个人中心</Link>
</li>
</ul>
</div>
);
}
export default TabBar;
编程式导航
import React from 'react';
import {
useNavigate} from "react-router-dom";
function NowPlaying(props) {
const navigate = useNavigate()
const handlePage = (params) => {
navigate(`/detail?id=${
params}`)
// search传参(URLsearch) /detail?id=100
// 路由传参 /detail/1000
}
return (
<div>
{
Array(20).fill(0).map((item,index) => index).map(item =>
<div key={
item} onClick={
() => {
handlePage(item)
}}>{
item}</div>
)
}
</div>
);
}
export default NowPlaying;
Detail.js
import React from 'react';
import {
useSearchParams} from "react-router-dom";
function Detail(props) {
const [searchParams, setSearchParams] = useSearchParams()
console.log({
searchParams})
console.log(searchParams.get('id')) // 获取传过来的参数
return (
<div>Detail
<button onClick={
() => {
setSearchParams({
id: 8})
}}>猜你喜欢</button>
</div>
);
}
export default Detail;
动态路由
//路由配置
<Route path="/detail/:id" element={
<Detail />}></Route>
// films.js
import React from 'react';
import {
useNavigate} from "react-router-dom";
function NowPlaying(props) {
const navigate = useNavigate()
const handlePage = (params) => {
navigate(`/detail/${
params}`)
}
return (
<div>
{
Array(20).fill(0).map((item,index) => index).map(item =>
<div key={
item} onClick={
() => {
handlePage(item)
}}>{
item}</div>
)
}
</div>
);
}
export default NowPlaying;
//detail.js
import React from 'react';
import {
useSearchParams, useParams} from "react-router-dom";
function Detail(props) {
//接受动态路由参数
const obj = useParams()
console.log(obj)// {id: 7}
return (
<div>Detail -{
obj.id}
<button onClick={
() => {
// setSearchParams({id: 8})
navigate('/detail/1000')
}}>猜你喜欢</button>
);
}
export default Detail;
路由拦截
{
/* element只会走一遍,只会走组件的生命周期,三木运算符只会走一遍,解决办法就是再封装一个组件*/}
<Route path="/center" element={
<AuthComponent>
{
/*需要鉴权的组件都可以放在AuthComponent*/}
<Center></Center>
</AuthComponent>}></Route>
//鉴权组件
function AuthComponent({
children}){
return localStorage.getItem('token') ? children : <Redirect to="/login"></Redirect>
}
路由模式
hashRouter
BrowserRouter: 需要后端配置支持
import logo from './logo.svg';
import {
BrowserRouter, HashRouter} from 'react-router-dom'
//HashRouter: 哈希模式
//BrowserRouter:浏览器模式
import TabBar from "./conponents/TabBar/Tabbar";
import './App.css';
import MRouter from "./router";
function App() {
return (
<BrowserRouter>
{
/*<HashRouter>*/}
<MRouter></MRouter>
<TabBar></TabBar>
{
/*</HashRouter>*/}
</BrowserRouter>
);
}
export default App;
类组件跳转方法
v6中是没有withRouter的,可进行自我封装
//filmItem
import React, {
Component} from 'react';
import WithRouter from "../../conponents/WithRouter";
class FilmIteMcLass extends Component {
render() {
console.log(this.props.history)
return (
<div>
<li onClick={
() => {
this.handleClick(this.props.item)
}}>{
this.props.item}</li>
</div>
);
}
handleClick(id){
console.log({
id})
this.props.history.push(`/detail/${
id}`)
}
}
export default WithRouter(FilmIteMcLass);
// 自我封装withRouter
import React from'react';
import {
useNavigate,useParams,useLocation } from'react-router-dom';
function WithRouter(Component) {
return function WithRouter(props) {
//react-hooks需要放在组件中,因此不建议放在匿名函数和箭头函数中,否则会报错
const push = useNavigate() //跳转
const match = useParams() // 获取传参
const location = useLocation() // 获取路径
return <Component {
...props} history={
{
push,match,location}}></Component>
}
}
export default WithRouter;
性能优化——路由懒加载
// 懒加载封装
function LazyLoad(path){
const Comp = React.lazy(() => import(`../views/${
path}`))
return(
<React.Suspense fallback={
<>加载中</>}>
<Comp></Comp>
</React.Suspense>
)
}
//使用
// 要删除import的路径
<Route path="nowPlaying" element={
LazyLoad("filmModules/NowPlaying")}></Route>
<Route path="/cinema" element={
LazyLoad("Cinema")}></Route>
懒加载的模块都会被单独抽象成一个js文件,因此要比项目中不适用懒加载的文件多。
useRoutes钩子配置路由
import React from 'react';
import {
Navigate, NavLink, Route, Routes, useRoutes} from "react-router-dom";
import Redirect from "../conponents/Redirect";
function MRouter(props) {
const element = useRoutes([
{
path: '/film',
element: LazyLoad("film"),
children:[
{
path:'',
element: <Redirect to="/film/nowPlaying"></Redirect>
},
{
path: 'nowPlaying',
element: LazyLoad("filmModules/NowPlaying")
},
{
path:'comingSoon',
element: LazyLoad('filmModules/ComingSoon')
}
]
},
{
path:'/cinema',
element: LazyLoad('Cinema')
},
{
path:'/login',
element:LazyLoad('Login')
},
{
path:'/center',
element:<AuthComponent> {
LazyLoad('Center')}</AuthComponent>
}
])
return (
element
);
}
function AuthComponent({
children}){
return localStorage.getItem('token') ? children : <Redirect to="/login"></Redirect>
}
function LazyLoad(path){
const Comp = React.lazy(() => import(`../views/${
path}`))
return(
<React.Suspense fallback={
<>加载中</>}>
<Comp></Comp>
</React.Suspense>
)
}
export default MRouter;
对比未使用钩子函数写的方法:
import React from 'react';
import {
Navigate, NavLink, Route, Routes} from "react-router-dom";
import Film from "../views/film";
// import Cinema from "../views/Cinema";
import Center from "../views/Center";
import Redirect from "../conponents/Redirect";
import NotFound from "../views/NotFound";
// import NowPlaying from "../views/filmModules/NowPlaying";
import ComingSoon from "../views/filmModules/ComingSoon";
import Detail from "../views/Detail";
import Login from "../views/Login";
function MRouter(props) {
return (
<Routes>
{
/*Route一定要包裹在Routes组件内部*/}
{
/* index表示: 不匹配其他子路由,只在父组件路由的时候显示该组件,用于嵌套路由*/}
<Route path="/film" element={
<Film />}>
{
/*index表示默认展示的子路由 与父路由展示同一路径*/}
<Route index element={
<Redirect to="/film/nowPlaying"></Redirect>} ></Route>
<Route path="/film/comingSoon" element={
<ComingSoon />}></Route>
{
/*相对路径写法: 相对于父路由的写法*/}
<Route path="nowPlaying" element={
LazyLoad("filmModules/NowPlaying")}></Route>
<Route path="comingSoon" element={
<ComingSoon />}></Route>
</Route>
<Route path="/cinema" element={
LazyLoad("Cinema")}></Route>
{
/* element只会走一遍,只会走组件的生命周期,三木运算符只会走一遍,解决办法就是再封装一个组件*/}
<Route path="/center" element={
<AuthComponent>
{
/*需要鉴权的组件都可以放在AuthComponent*/}
<Center></Center>
</AuthComponent>}></Route>
<Route path="/detail/:id" element={
<Detail />}></Route>
<Route path="/login" element={
<Login></Login>}></Route>
{
/* 路由重定向*/}
{
/* *表示万能匹配,当以上路由都未匹配到时,才会走下面的匹配,渲染film组件*/}
{
/* <Route path="*" element={<Navigate to="/film"></Navigate>}></Route>*/}
<Route path="/" element={
<Redirect to="/film"></Redirect>}></Route>
<Route path="*" element={
<NotFound></NotFound>}></Route>
</Routes>
);
}
function AuthComponent({
children}){
return localStorage.getItem('token') ? children : <Redirect to="/login"></Redirect>
}
function LazyLoad(path){
const Comp = React.lazy(() => import(`../views/${
path}`))
return(
<React.Suspense fallback={
<>加载中</>}>
<Comp></Comp>
</React.Suspense>
)
}
export default MRouter;
react-ruter6的写法已经和vue很相像了,特别是useRouteList钩子的封装,基本上和vue是一样的