react-router-dom 【V6新变化】
react-router-dom
react-router-dom v6整体体验相对于v5,体验要好很多,最大的一个改变,就是曾经的Route不可嵌套,整个路由配置必须拆分成若干小块,除非通过react-router-config这种插件,才可以实现对整个路由的管理,然而现在,不需要任何插件就可以实现对路由配置的管理。
安装
npm install --save react-router-dom history
react,react-router-dom以及相关插件版本
"dependencies": {
"history": "^5.1.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.0.2"
}
如果是自己通过webpack配置的项目,一定要在devServe中配置historyApiFallback,以及output.publicPath解决history模式页面刷新后出现404情况。
devServer: {
port,
host,
hot: true,
open: true,
historyApiFallback:{
disableDotRule: true
}
},
// 以及 `output` 中的 publicPath
output: {
path: path.resolve(__dirname, "../dist"),
filename: "[name].[chunkhash].js",
publicPath: '/'
},
使用
在文件中直接渲染Router.tsx
// idex.tsx
import React from "react";
import ReactDOM from "react-dom";
import Router from "./router/Router";
import "./index";
ReactDOM.render( , document.getElementById("root"));
【1】Routes组件替换V5的Switch组件
- Route组件必须使用Routes嵌套
//Router.tsx
import React from 'react';
import {BrowserRouter,Route,Routes} from 'react-router-dom';
import Home from '../home/Home';
import Goods from '../goods/Goods';
import Customer from '../customer/Customer';
export defealt function Router(){
//所有的路由配置均在BrowserRouter内部
return(
{/* 使用 Routes 替换曾经的 Switch */}
} />
} />
} />
)
}
【2】跳转
- 通过Link组件跳转
//Customer.tsx
import React from 'react';
import {Link} from "react-router-dom";
export default function Customer(){
return(
Customer Page
to Goods
)
}
- 通过useNavigate方法跳转
//Goods.tsx
import React from 'react';
import {useNavigate} from 'react-router-dom';
export default function Goods(){
const navigate = useNavigate();
const handleClickToHome = ()=>{
navigate("/");
//history的replace模式
//navigate('/',{replace:true})
};
return (
Goods Page
)
}
【3.匹配未定义的路由】
- v6移除了Redirect组件,改用Navigate组件。
// Router.tsx
import React from "react";
import { BrowserRouter, Route, Routes, Navigate } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";
export default function Router() {
{/* 所有的路由配置均在 BrowserRouter 内部 */ }
return (
{/* 使用 Routes 替换曾经的 Switch */}
} />
} />
} />
{/* 重定向到首页 */}
} />
{/* 或者跳转到 NotFound */}
{/* } /> */}
);
}
【4】嵌套路由与动态路由
- 嵌套路由的path可以不用写父级,会直接拼写;
- 动态路由通过:style的形式实现;
- 由于/goods/list的匹配度大于/goods/*,所以输入精确地址会精确匹配,而不是匹配到动态路由;
- 嵌套路由必须在父级追加 Outlet 组件,作为子级组件的占位符,类似于vue-router中的router-view。
// Router.tsx
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";
import GoodsDetail from "../goods/goods-detail/GoodsDetail";
import GoodsList from "../goods/goods-list/GoodsList";
export default function Router() {
return (
}>
} >
{/* 动态路由 */}
}/>
}/>
} >
} />
);
}
// Home.tsx
import React from "react";
import { Outlet, Link } from "react-router-dom";
export default function Home() {
return (
Home
to goods
to customer
);
}
// Goods.tsx
import React from "react";
import { useNavigate, Outlet } from "react-router-dom";
export default function Goods() {
const navigate = useNavigate();
const handleClickToHome = () => {
navigate("/");
// history 的 replace 模式
// navigate("/", { replace: true });
};
return (
Goods Page
{/* 子路由的占位组件 */}
);
}
【5】获取路由的参数
- useParams获取动态路由的值;
- useSearchParams获取查询字符串的值。
// GoodsDetail.tsx
import React,{ useEffect } from "react";
import { useParams, useSearchParams } from "react-router-dom";
export default function GoodsDetail() {
// 获取动态路由的值
const params = useParams();
// 获取查询字符串的值
const [searchParams, setSearchParams] = useSearchParams();
useEffect(() => {
// 一个对象,key 为动态字符串的 key
console.log(params); // {id: '123'}
// 一个对象,但是不可直接点出属性
console.log(typeof searchParams); // object
// 输入 http://localhost:3304/goods/123?name=nihao
console.log(searchParams.get("name")); // nihao
}, []);
const handleAddParams = () => {
// 修改 查询字符串 的数据
setSearchParams({
name:"xxx"
});
};
return (
GoodsDetail Page
);
}
【6】默认路由
-
当页面又多个子路由,比如在/goods时,页面展示商品列表;/goods/:id时,展示某个商品的详情。
-
Route的Index属性就是用来展示默认子路由的。
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";
import GoodsDetail from "../goods/goods-detail/GoodsDetail";
import GoodsList from "../goods/goods-list/GoodsList";
export default function Router() {
return (
}>
} >
{/* 默认 子路由 ,在页面 路由为 /goods ,会展示该子路由 */}
}/>
}/>
} >
} />
);
}
【7】通过配置实现路由管理
- useRoutes可以讲数组对象形式的路由,直接在页面上使用。
// 入口文件,src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index";
ReactDOM.render((
), document.getElementById("root"));
// src/router/routes.tsx
import React from "react";
import { RouteObject } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";
import GoodsDetail from "../goods/goods-detail/GoodsDetail";
import GoodsList from "../goods/goods-list/GoodsList";
const routes: RouteObject[] = [
{
path: "/",
element: ,
children: [
{
path: "/goods",
element: ,
children: [
{ index: true, element: },
{ path: ":id", element: }
]
},
{
path: "/customer",
element: ,
},
{
path: "*",
element: ,
},
]
}
];
export default routes;
// src/App.tsx
import React from "react";
import { useRoutes } from "react-router-dom";
import routes from "./router/routes";
export default function App() {
const element = useRoutes(routes);
return (
<>
{element}
>
);
}