react-router-dom5升级到6

前言

升级前版本为5.1.2

下载与运行

下载

npm install react-router-dom@6

运行

运行发现报错:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将node_modules删除,重新执行npm i即可

运行发现如下报错

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是因为之前有引用react-router-dom.min,v6中取消了该文件,所以未找到文件导致报错。

将引用变为react-router-dom即可解决。

再次运行发现如下报错:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是因为react-router-dom6取消了withRouter,如果想要获取路由地址,需要使用useLocation

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

变为

在这里插入图片描述

再次运行发现如下报错:

在这里插入图片描述

按照官网进行如下修改:

Switch 被替换为 Routes

v5 时代的第一个被替代的是Switch组件。该Switch组件用于包装我们的路由,它确保每次只加载一个匹配的路由。但这在 v6 中不再存在。我们使用Routes组件来替换Switch。请注意,我们仍然需要导入BrowserRouter包装我们的应用程序,就像在 v5 中所做的那样。

在 v5 中,我们是这样做:

import {
    
     BrowserRouter, Switch } from "react-router-dom";

function App() {
    
    
    return (
        <BrowserRouter>
            <div className="App">
                <Switch>
                    {
    
    /* 路由Route在此定义 */}
                </Switch>
            </div>
        </BrowserRouter>
    );
}
export default App

但在 v6 中,我们将这样做

import {
    
     BrowserRouter, Routes } from "react-router-dom";

function App() {
    
    
    return (
        <BrowserRouter>
            <div className="App">
                <Routes>
                    {
    
    /* Switch 会被改成 Routes */}
                    {
    
    /* 路由Route在此定义 */}
                </Routes>
            </div>
        </BrowserRouter>
    );
}

export default App

注意:v5的Switch中可以包含非Route元素,但Routes中只能存在Route,否则会报错。
在这里插入图片描述

Route组件使用更新

尽管该Route组件在 v6 中仍然保留一个位置,但我们定义它的使用方式与我们在 v5 中的方式不同。我们将不再以 v5 中的任何方式放置我们想要渲染的组件,而是统一将其作为elementprop的值传递。

没有exact配置

v5 中,不添加exact作为Route组件props的话,如果 URL 以 path 关键字开头,则路径将匹配,因为匹配过程是从上到下的顺序。但在 v6 中,我们将不再需要该exact配置,因为路径模式匹配算法已更改,并且现在更加增强。

在 v5 中,我们这样做了:

<Switch>
   {
    
    /* 三种Route组件使用定义 */}
   <Route path="/signup" component={
    
    Product} />
   {
    
    /* 或 */}
   {
    
    /* 这个方法允许我们将 props 传递给渲染的组件 */}
   <Route path="/games">
       <Product id={
    
    2} />
   </Route>
   {
    
    /* 或是通过render函数 */}
   <Route path="/games" render={
    
    (props) => <Product {
    
    ...props} />} />
</Switch>

在 v6 中,

<Routes>
   {
    
    " "}
   <Route path="/games" element={
    
    <Product />} />
   {
    
    /* 带有props的渲染组件 */}
   <Route path="/movies" element={
    
    <Product id={
    
    200} category="shirt" />} />
</Routes>

Links 和 NavLinks

LinkNavLink组件仍然可以运行在V6。Link组件使用与在 v5 的时候保持一样,但使用NavLink组件时,删除了activeClassNameactiveStyle prop。在 v5 中,activeClassNameprop 用于在链接激活后自动将一些 CSS 类应用于链接,同时activeStyle允许我们在链接激活时向链接添加内部样式。

但是在 v6 中,现在可以使用一个函数来获取有关链接活动状态的信息。该函数的参数是一个具有属性的对象isActive。此属性在链接处于活动状态时为,在非活动时为isActive的值允许我们使用条件表达式来指示活动样式或类名。

在 v5 中,

import {
    
    NavLink} from “react-router-dom”

{
    
    /* … */}
<NavLink
   to="/product"
   style={
    
    {
    
     color: "#689" }}
   activeStyle={
    
    {
    
     color: "#3072c9" }}
   className="nav_link"
   activeClassName="active"
>
   Products
</NavLink>

但在 v6 中,我们将这样做:

<NavLink
   to="/product"
   style={
    
    ({
     
      isActive }) => ({
    
     color: isActive ? "#3072c9" : "#689" })}
   className={
    
    ({
     
      isActive }) => `link${
      
      isActive ? " active" : ""}`}
>
   Product
</NavLink>

Navigate替代Redirect

在 v5 中,使用该Redirect组件将一个页面带到另一个页面,但它不再从 v6 中的 react-router-dom 导出。它已被Navigate组件替换。

在 v5 中,

<Route path="/faq">
   <Redirect to="/about" />
</Route>
<Route path="/about" component={
    
    About} />

但在 v6 中,

<Route path="/games" element={
    
    <Navigate to="/about" />} />;
<Route path="/games" element={
    
    <About />} />;

需要注意的是,如果只是按照Navigate上面代码片段中的方式添加组件,它只会将导航到该路径的导航推送到导航堆栈中,但是如果我们打算用新页面替换当前页面,我们将 replace 属性添加到Navigate组件中,如下所示:

<Route path="/games" element={
    
    <Navigate replace to="/about" />} />;

嵌套路由

顾名思义,嵌套路由是放置在另一个路由中的路由。它们用于在子组件中呈现更具体的信息。在 v6 中,将嵌套路由放置为父路由的子路由。然后引入Outlet组件,它是从渲染组件中的 react-router-dom 导出的,用于指定希望嵌套信息显示在哪里。Outlet 组件不是必需的,但它使代码更清晰。
在 v5 中,

import {
    
     useRouteMatch } from "react-router-dom";
function App() {
    
    
   return (
       <BrowserRouter>
           <Switch>
               <Route exact path="/about" component={
    
    About} />
               <Route path="/product" component={
    
    Product} />
           </Switch>
       </BrowserRouter>
   );
}

function Product() {
    
    
   let match = useRouteMatch();
   return (
       <div>
           <Switch>
               {
    
    /* match.path 返回父路由中指定的路径。在这种情况下,它是“/product" */}
               <Route path={
    
    `${
      
      match.path}`}>
                   <AllProducts />
               </Route>
               {
    
    /* 匹配 /product/:id */}
               <Route path={
    
    `${
      
      match.path}/:id`}>
                   <ProductDetail />
               </Route>
           </Switch>

       </div>
   );
}

在 v6 中,

import {
    
     Outlet } from "react-router-dom";

function App() {
    
    
   return (
       <Routes>
           <Route path="/about" element={
    
    <About />} />
           <Route path="/product" element={
    
    <Product />}>
               {
    
    /* 这里嵌套路由的路径是相对于父路由的路径的。 */}
               {
    
    /* 这里变成 "/product/" */}
               <Route path="/" element={
    
    <AllProducts />} />
               {
    
    /* 这里变成 "/product/:id" */}
               <Route path="/:id" element={
    
    <ProductDetail />} />

           </Route>
       </Routes>
   );
}

function Product() {
    
    
   return (
       <Container>
           <>
               <div>Product</div>
               {
    
    /* 父组件的其他内容 */}
           </>
           {
    
    /* 这是嵌套信息开始的地方 */}
           <Outlet />
       </Container>
   );
}

useNavigate代替useHistory

当用户因路径上发生的事件(例如单击按钮、API 请求完成等)而被重定向时,就会发生程序化导航。在 v5 中,可以使用useHistory钩子来执行以下操作:

import {
    
     useHistory } from "react-router-dom";

function Product() {
    
    
   const history = useHistory();

   const handleClick = () => {
    
    
       //这会将新路线推送到导航堆栈的顶部
       history.push("/new-route");
       history.push({
    
    pathname:"/new-route",state:{
    
    p1:xxx});  // 传参

       //这会将当前路线替换为导航堆栈中的新路由
       history.replace("/new-route");
   };

   return (
       <div>
           <button>点击我重定向到新路由</button>
       </div>
   );
}

但是在 v6 中,useHistoryhook 被替换为useNavigatehook,并且以不同的方式使用它。

import {
    
     useNavigate } from "react-router-dom";

function Product() {
    
    
   const navigate = useNavigate();

   const handleClick = () => {
    
    
       //这会将新路线推送到导航堆栈的顶部
       navigate("/new-route");
	   navigate("/new-route",{
    
    state:{
    
    p1:xxx}});  // 传参

       //这会将当前路线替换为导航堆栈中的新路由
       navigate("/new-route", {
    
     replace: true });
   };

   return (
       <div>
           <button>点击我重定向到新路由</button>
       </div>
   );
}

一件很酷的事情是以在导航堆栈上任意前进和后退。通过使用正数作为上述参数navigate(),路由会向前移动该步数。负数向后做同样的事情

// Goes forward
navigate(1)
// Goes forward twice
navigate(2)
// Goes backward
navigate(-1)
// Goes backward three times
navigate(-3)

删除Prompt组件

Prompt如果有未保存的更改,v5 中的组件可防止意外离开页面。但是 react-router 团队并没有将它包含在 v6 中,也没有替代方案。因此,如果你需要该功能,你可以手动实现它或返回到 v5。

除了不包括Prompt在当前版本(v6)中,useBlockerusePrompt都不起作用。react-router 团队虽然在官方文档中表示,他们目前正在努力将其添加回 v6,但不是针对 6.x 的第一个稳定版本。

注意

react-router-dom5的Switch可以嵌套Redirect

但react-router-dom6的Routes中只可以存在Route和Route.Fragment

v5的Router写法,需要利用history

import {
    
     createBrowserHistory } from "history"
const customHistory = createBrowserHistory()

const Root = () => {
    
    
	return (
		<Router history={
    
    customHistory}>
				......
		</Router>
	)
}

v6直接更改路由引入方式即可

import {
    
     BrowserRouter } from "react-router-dom"

const Root = () => {
    
    
	return (
		<BrowserRouter>
				......
		</BrowserRouter>
	)
}

猜你喜欢

转载自blog.csdn.net/owo_ovo/article/details/135307819
今日推荐