1.Router(V6)简介
2.对比V5
3.用法详解
3.1一级路由和多级路由
安装
3.2指定默认路由
3.3路由重定向
3.4 404
3.5代码
import React from 'react'
import {Navigate, Route,Routes,} from "react-router-dom"
import Film from "../views/Film"
import Cinema from "../views/Cinema"
import Center from "../views/Center"
import NotFound from "../views/NotFound"
export default function Mrouter() {
return (
<div>
<Routes>
{}
{}
<Route path="/film" element={<Film />}></Route>
<Route path="/cinema" element={<Cinema />}></Route>
<Route path="/center" element={<Center />}></Route>
{}
<Route path="/" element={<Navigate to="/film"></Navigate>}></Route>
{}
<Route path="*" element={<NotFound/>}></Route>
</Routes>
</div>
);
}
3.6路由嵌套(maizuo.com为例)
路由嵌套有两种形式 二级路由不代表路由嵌套,如果组件整个被替换,只是路径上嵌套比如/cinema/search,搜索组件完全替换了cinema组件,而film组件下的两个二级路由是Nowplaying和Comingsoon,这两个组件共用film组件的轮播图 比如说这两个组件,上面部分的轮播图是共用的,只有下面的内容是替换的 那么会将这两个组件放在film组件的哪个位置呢,怎么让它们在轮播图的下面而不是上面,就需要路由容器占位了 相对路径的写法:
像这种组件完全替换,实际上是平级的组件,但是路径是二级路径的代码需要这样写:
import React from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import Film from "../views/Film";
import Cinema from "../views/Cinema";
import Search from "../views/Search";
import Center from "../views/Center";
import NotFound from "../views/NotFound";
import Nowplaying from "../views/films/Nowplaying";
import Comingsoon from "../views/films/Comingsoon";
export default function Mrouter() {
return (
<div>
<Routes>
{}
{}
<Route path="/film" element={<Film />}>
{}
{}
{}
{}
{}
<Route index element={<Navigate to="/film/nowplaying"></Navigate>} />
{}
<Route path="nowplaying" element={<Nowplaying />} />
<Route path="comingsoon" element={<Comingsoon />} />
</Route>
<Route path="/cinema" element={<Cinema />}></Route>
<Route path="/cinema/search" element={<Search />}></Route>
<Route path="/center" element={<Center />}></Route>
{}
<Route path="/" element={<Navigate to="/film"></Navigate>}></Route>
{}
<Route path="*" element={<NotFound />}></Route>
</Routes>
</div>
);
}
4.声明式导航和编程式导航
a标签相当于于声明式导航 location相当编程式导航
4.1声明式导航
使用NavLink选项卡,选中哪个哪个会自动有class=active,可以给active设置高亮颜色,但是由于很多人一起开发,别人的acive也会影响到我们的颜色,所以要取另外的名,className给NavLink传了个属性,支持回调函数的写法,回调函数接收到一个形参,解构出来isActive Tabbar.js
import React from 'react'
import {NavLink} from "react-router-dom"
export default function Tabbar() {
return (
<div>
<ul>
<li>
{" "}
<NavLink
to="/film"
className={({ isActive }) => (isActive ? "xxactive" : "")}
>
电影
</NavLink>
</li>
<li>
{" "}
<NavLink
to="/cinema"
className={({ isActive }) => (isActive ? "xxactive" : "")}
>
影院
</NavLink>
</li>
<li>
<NavLink
to="/center"
className={({ isActive }) => (isActive ? "xxactive" : "")}
>
我的
</NavLink>
</li>
</ul>
</div>
);
}
4.2编程式导航
更适合携带参数跳转到另一个页面 使用useNavigate跳转,还有一种方法是this.props.history,但是这种方法有的组件不一定能拿到this.props的值
4.21query(URL Search传参 /detail?id=1000)
Nowplaying.js
import React, { useEffect, useState} from "react";
import {useNavigate} from "react-router-dom"
import axios from "axios";
export default function Nowplaying() {
const [list, setList] = useState([]);
const navigate = useNavigate();
useEffect(() => {
axios(
"https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=4238375",
{
headers: {
"X-Client-Info":
'{"a":"3000","ch":"1002","v":"5.2.0","e":"16460383564094280654127105","bc":"110100"}',
"X-Host": "mall.film-ticket.film.list",
},
}
).then((res) => {
setList(res.data.data.films);
});
}, []);
function handleChangePage(id) {
navigate(`/detail/?id=${id}`);
}
return (
<div>
<ul>
{list.map((item) => (
<li
key={item.filmId}
onClick={() => {
handleChangePage(item.filmId)
}}
>
{item.name}
</li>
))}
</ul>
</div>
);
}
Detail.js
import React from "react";
import { useSearchParams } from "react-router-dom";
export default function Detail() {
const [searchParams, setsearchParams] = useSearchParams();
console.log(searchParams.get("id"));
return <div>Detail
<button onClick={()=>setsearchParams({'id':1000})}>猜你喜欢</button>
</div>;
}
4.22路由传参 (/detail/1000) 动态路由
Nowplaying.js
import React, { useEffect, useState} from "react";
import {useNavigate} from "react-router-dom"
import axios from "axios";
export default function Nowplaying() {
const [list, setList] = useState([]);
const navigate = useNavigate();
useEffect(() => {
axios(
"https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=4238375",
{
headers: {
"X-Client-Info":
'{"a":"3000","ch":"1002","v":"5.2.0","e":"16460383564094280654127105","bc":"110100"}',
"X-Host": "mall.film-ticket.film.list",
},
}
).then((res) => {
setList(res.data.data.films);
});
}, []);
function handleChangePage(id) {
navigate(`/detail/${id}`)
}
return (
<div>
<ul>
{list.map((item) => (
<li
key={item.filmId}
onClick={() => {
handleChangePage(item.filmId)
}}
>
{item.name}
</li>
))}
</ul>
</div>
);
}
Detail.js
import React from "react";
import { useSearchParams, useParams, useNavigate } from "react-router-dom";
export default function Detail() {
const navigate =useNavigate()
const params=useParams()
console.log(params.myid);
return (
<div>
Detail
{}
{}
{}
<button onClick={() => navigate("/detail/1000")}>猜你喜欢</button>
</div>
);
}
5.路由拦截
自己封装的Redirect组件 Login.js
import React from 'react'
import { useNavigate } from 'react-router-dom';
import Redirect from '../components/Redirect'
export default function Login() {
const navigate=useNavigate()
return (
<div>
<input type="text"></input>
<button type="button" onClick={()=>{localStorage.setItem("token","ss");
navigate("/center");
}}>登录</button>
</div>
)
}
index.js
import React from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import Redirect from "../components/Redirect"
import Film from "../views/Film";
import Cinema from "../views/Cinema";
import Search from "../views/Search";
import Center from "../views/Center";
import NotFound from "../views/NotFound";
import Detail from "../views/Detail"
import Login from "../views/Login"
import Nowplaying from "../views/films/Nowplaying";
import Comingsoon from "../views/films/Comingsoon";
export default function Mrouter() {
return (
<div>
<Routes>
{}
{}
<Route path="/film" element={<Film />}>
{}
{}
{}
{}
{}
<Route index element={<Navigate to="/film/nowplaying"></Navigate>} />
{}
<Route path="nowplaying" element={<Nowplaying />} />
<Route path="comingsoon" element={<Comingsoon />} />
</Route>
<Route path="/cinema" element={<Cinema />}></Route>
<Route path="/cinema/search" element={<Search />}></Route>
{}
{}
<Route
path="/center"
element={<AuthComponent>
<Center></Center>
</AuthComponent>}></Route>
<Route path="/login" element={<Login />}></Route>
{}
{}
<Route path="/detail/:myid" element={<Detail />}></Route>
{}
<Route path="/" element={<Navigate to="/film"></Navigate>}></Route>
{}
<Route path="*" element={<NotFound />}></Route>
</Routes>
</div>
);
}
function AuthComponent({children}){
const isLogin=localStorage.getItem("token")
return isLogin?children:<Redirect to="/login"/>
}
6.路由模式
BrowserRouter更像平时我们访问的路径,但是需要后端同步配置一下,不然会返回404 HashRouter会让路径多一个#符号
7.withRouter/类组件(自己封装)跳转方法
被Route包裹的组件会被赋予this.props.history,match等方法,但是被它包裹的组件的子组件没有这个方法,用withRouter组件可以实现,但是V6中没有这个方法了,需要自己封装 函数组件中如果要跳转网页,其实也用不到,可以用navigate(任何组件都可用),但是类组件没有hooks,需要封装withRouter方法
函数组件:将每个li变成一个新的组件FilmItem Nowplaying.js
import React, { useEffect, useState} from "react";
import axios from "axios";
import FilmItem from "./FilmItem";
export default function Nowplaying() {
const [list, setList] = useState([]);
useEffect(() => {
axios(
"https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=4238375",
{
headers: {
"X-Client-Info":
'{"a":"3000","ch":"1002","v":"5.2.0","e":"16460383564094280654127105","bc":"110100"}',
"X-Host": "mall.film-ticket.film.list",
},
}
).then((res) => {
setList(res.data.data.films);
});
}, []);
return (
<div>
<ul>
{list.map((item) => (
<FilmItem key={item.filmId} {...item}></FilmItem>
))}
</ul>
</div>
);
}
FilmItem.js
import React from "react";
import { useNavigate } from "react-router-dom";
export default function FilmItem(item) {
const navigate = useNavigate();
function handleChangePage(id) {
navigate(`/detail/${id}`);
}
return (
<div>
<li
onClick={() => {
handleChangePage(item.filmId);
}}
>
{item.name}
</li>
</div>
);
}
类组件封装withrouter withRouter.js
import React from 'react'
import { useNavigate,useParams,useLocation } from 'react-router-dom'
export default function withRouter(Component) {
return function (props){
const push = useNavigate();
const params = useParams();
const location = useLocation()
return <Component {...props} history={{ push, params,location }} />;
}
}
FilmItem.js
import React, { Component } from "react";
import withRouter from "../../components/withRouter";
class FilmItem extends Component {
handleChangePage(id){
this.props.history.push(`/detail/${id}`);
console.log(this.props.history);
}
render() {
console.log(this.props);
return (
<div>
<li
onClick={() => {
this.handleChangePage(this.props.filmId);
}}
>
{this.props.name}
</li>
</div>
);
}
}
export default withRouter(FilmItem)
8.路由懒加载
由于路由过多,导致首页加载慢,渲染慢,我们使用路由懒加载后是按需加载且只加载一次 可以看到再次进入cinema不再加载,只加载了第一次 写成路由懒加载的写法后: router文件夹下的index.js
import React from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import Redirect from "../components/Redirect";
export default function Mrouter() {
return (
<div>
<Routes>
{}
{}
<Route path="/film" element={LazyLoad("Film")}>
{}
{}
{}
{}
{}
<Route index element={<Navigate to="/film/nowplaying"></Navigate>} />
{}
{}
{}
<Route path="nowplaying" element={LazyLoad("films/Nowplaying")} />
<Route path="comingsoon" element={LazyLoad("films/Comingsoon")} />
</Route>
{}
<Route path="/cinema" element={LazyLoad("Cinema")}></Route>
<Route path="/cinema/search" element={LazyLoad("Search")}></Route>
{}
{}
<Route
path="/center"
element={<AuthComponent>{LazyLoad("Center")}</AuthComponent>}
></Route>
<Route path="/login" element={LazyLoad("Login")}></Route>
{}
{}
<Route path="/detail/:myid" element={LazyLoad("Detail")}></Route>
{}
<Route path="/" element={<Navigate to="/film"></Navigate>}></Route>
{}
<Route path="*" element={LazyLoad("NotFound")}></Route>
</Routes>
</div>
);
}
function AuthComponent({ children }) {
const isLogin = localStorage.getItem("token");
return isLogin ? children : <Redirect to="/login" />;
}
const LazyLoad = (path) => {
const Comp = React.lazy(() => import(`../views/${path}`));
return (
<React.Suspense fallback={<>加载中...</>}>
<Comp />
</React.Suspense>
);
};
9.useRoutes钩子配置路由
路由改成钩子配置路由 router下的index.js
import React from "react";
import { useRoutes, Navigate } from "react-router-dom";
import Redirect from "../components/Redirect";
export default function Mrouter() {
const element = useRoutes([
{
path: "/film",
element: LazyLoad("Film"),
children: [
{
path: "",
element: <Redirect to="/film/nowplaying"></Redirect>,
},
{
path: "nowplaying",
element: LazyLoad("films/Nowplaying"),
},
{
path: "comingsoon",
element: LazyLoad("films/Comingsoon"),
},
],
},
{
path: "/cinema",
element: LazyLoad("Cinema"),
},
{
path: "/cinema/search",
element: LazyLoad("Search"),
},
{
path: "/login",
element: LazyLoad("Login"),
},
{
path: "/center",
element: <AuthComponent>{LazyLoad("Center")}</AuthComponent>,
},
{
path: "/detail/:myid",
element: LazyLoad("Detail"),
},
{
path: "/",
element: <Navigate to="/film"></Navigate>,
},
{
path: "*",
element: LazyLoad("NotFound"),
},
]);
return element;
}
function AuthComponent({ children }) {
const isLogin = localStorage.getItem("token");
return isLogin ? children : <Redirect to="/login" />;
}
const LazyLoad = (path) => {
const Comp = React.lazy(() => import(`../views/${path}`));
return (
<React.Suspense fallback={<>加载中...</>}>
<Comp />
</React.Suspense>
);
};
|