草庐IT

react-router-dom V6

Monkey_Kcode 2023-04-14 原文

目录

1. 前言

2. 变更概览

将 Switch 升级为 Routes

路由匹配组件参数 由 component 改为 element

相对路径识别(子路由不需要补全父路由的path,react会自动补全)

用 useNavigate 替代  useHistory  

废弃 Redirect 标签,使用 Navigate 标签实现路由重定向

优化路由嵌套,添加 outlet 标签

使用 index 标识默认路由

添加 useResolvedPath  hooks 

添加 useSearchParams 读取和设置url参数

link 标签跳转的path 将支持 . 和 .. 这种语法(类比于 terminal 中的 cd .. 返回上级菜单 ) 

 path 通配符将只支持 * 和 :(以前的?等将不再支持) 

添加 useOutletContext 用于 路由之间共享状态


1. 前言

伴随React18的到来,React的路由也有 5.# 版本更新到了 V6版本,接下来让我们总结下 V6 版本的更新内容,对我们的使用有什么影响。

其实官网文档写的很清晰,我这里只是做个总结,大家也可直接移步官网: React Router | Overviewhttps://reactrouter.com/docs/en/v6/getting-started/overview

2. 变更概览

  • 将 Switch 升级为 Routes

  • 路由匹配组件参数 由 component 改为 element

// before V6 
<Switch>
    <Route path="/home" component={Home}></Route>
</Switch>

// V6 
<Routes>
    // 注意,这里是 jsx 语法,需要配合标签, 传参也可以直接写为组件传参
    <Route path="/home" element={<Home animate={true} />}></Route>
</Routes>

  • 相对路径识别(子路由不需要补全父路由的path,react会自动补全)

<Routes>
   <Route path="user" element={<Invoices />}>
       <Route path=":id" element={<Invoice />} />
       <Route path="me" element={<SentInvoices />} />
   </Route>
</Routes>

// path: /user
// path: /user/:id
// path: /user/me
  • 用 useNavigate 替代  useHistory  

// 函数组件使用编程式跳转

// V5
let history = useHistory();
history.push("/home");

// V6
let navigate = useNavigate();
navigate('/home')

// 如果需要类比 history.replace, 可以添加参数replace为true
navigate(to, { replace: true })

// 如果需要类比隐式传参,可以添加参数 state
navigate(to, { state })

// 同时 link 也添加了单独的参数 state
<Link to="/home" state={state} />


// 如果需要类比 goBack,go等语法,也可直接在 navigate中 传层级参数
// 等价于 history.go(-1)
<button onClick={() => navigate(-2)}>
    Go 2 pages back
</button>
<button onClick={() => navigate(-1)}>Go back</button>
<button onClick={() => navigate(1)}>
    Go forward
</button>
<button onClick={() => navigate(2)}>
    Go 2 pages forward
</button>
  • 废弃 Redirect 标签,使用 Navigate 标签实现路由重定向

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

function App() {
  return <Navigate to="/home" replace state={state} />;
}

/*
    v5默认<Redirect />使用 replace 逻辑
    v6默认<Navigate />使用 push 逻辑 ,可以通过参数设置为 replace
*/
  • 优化路由嵌套,添加 outlet 标签

import {
    Routes,
    Route,
    Link,
    Outlet,
    BrowserRouter
  } from "react-router-dom";
  
  function Layout() {
    return (
      <div>
        <h1>Welcome to the V6!</h1>
        <nav>
          <Link to="product">产品页</Link>
          <br/>
          <Link to="detail">详情页</Link>
        </nav>
        <div className="content">
  
          {/* 子路由将会显示在这里,用outlet占位 */}
          <Outlet />
  
        </div>
      </div>
    );
  }
  
  function Product() {
    return <h1>产品页</h1>;
  }
  
  function Detail() {
    return <h1>详情页</h1>;
  }

  function App() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path="/" element={<Layout />}>
                    <Route path="product" element={<Product />} />
                    <Route path="detail" element={<Detail />} />
                </Route>
            </Routes>
        </BrowserRouter>
    );
  }
  
  export default App
  • 使用 index 标识默认路由

<Routes>
   <Route path="/" element={<Layout />}>
       <Route index element={<Activity />} />
       <Route path="invoices" element={<Invoices />} />
       <Route path="activity" element={<Activity />} />
   </Route>
</Routes>
  • 添加 useResolvedPath  hooks 

在 V5版本的文档中,只有四个比较重要的hooks,分别是 useHistory, useLocation, useParams, useRouteMatch,V5文档:

React Router: Declarative Routing for React.jshttps://v5.reactrouter.com/web/api/Hooks/useparams而 V6 版本又添加了一些hooks,我们简单列举几个可能会用到的,完整版移步官网:

https://reactrouter.com/docs/en/v6/api#resolvepathhttps://reactrouter.com/docs/en/v6/api#resolvepath

由于V6的相对路径识别特性,有时我们需要获取完整的url路径,可以使用 useRelovedPath

useRelovedPath 必须接收一个参数,可以为空字符串

  <Route path="/" element={<Layout />}>
       <Route path="product" element={<Product />} />
       <Route path="detail" element={<Detail />} />
  </Route>

  function Product() {
    const path = useResolvedPath('id');
    console.log(path);  // output: { pathname: '/product/id' }
    return <h1>产品页</h1>;
  }
  
  function Detail() {
    const path = useResolvedPath('');
    console.log(path);   // output: { pathname: '/detail' }
    return <h1>详情页</h1>;
  }
  • 添加 useSearchParams 读取和设置url参数

useSerachParams 可以读取和修改当前位置url的查询参数(?id=123), 具体使用方式类比于 useState,但用法略有不同。

获取某个searchParams: searchParams.get(key)

设置某个searchParams: setSearchParams({key:value})

import {
    Routes,
    Route,
    Link,
    Outlet,
    BrowserRouter,
    useResolvedPath,
    useSearchParams
  } from "react-router-dom";
  
  function Layout() {
    return (
      <div>
        <h1>Welcome to the V6!</h1>
        <nav>
          <Link to="product">产品页</Link>
          <Link to="detail?id=123">详情页</Link>
        </nav>
        <div className="content">
  
          <Outlet />
  
        </div>
      </div>
    );
  }
  
  function Product() {
    const path = useResolvedPath('id');
    console.log(path);
    return <h1>产品页</h1>;
  }
  
  function Detail() {
    const [searchParams,setSearchParams] = useSearchParams()

    const handleSubmit = ()=>{
        // 输入键值对,设置对应的 search 参数
        setSearchParams({id:456})
    }

    // 通过 get 方法获取key对应的value
    console.log(searchParams.get('id'));

    return (
        <h1>
            详情页 : {searchParams.get('id')} 
            <br/>
            <button onClick={()=>handleSubmit()}>update searchParams</button>
        </h1>
    );
  }

  function App() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path="/" element={<Layout />}>
                    <Route path="product" element={<Product />} />
                    <Route path="detail" element={<Detail />} />
                </Route>
            </Routes>
        </BrowserRouter>
    );
  }
  
  export default App
  • link 标签跳转的path 将支持 . 和 .. 这种语法(类比于 terminal 中的 cd .. 返回上级菜单 ) 

// 这里直接拿了官网的示例

function App() {
  return (
   <BrowserRouter>
     <Routes>
       <Route path="users" element={<Users />}>
         <Route path=":id" element={<UserProfile />} />
       </Route>
     </Routes>
   <BrowserRouter>

  );
}

function Users() {
  return (
    <div>
      <h2>
        {/* This links to /users - the current route */}
        <Link to=".">Users</Link>
      </h2>

      <ul>
        {users.map((user) => (
          <li>
            {/* This links to /users/:id - the child route */}
            <Link to={user.id}>{user.name}</Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

function UserProfile() {
  return (
    <div>
      <h2>
        {/* This links to /users - the parent route */}
        <Link to="..">All Users</Link>
      </h2>

      <h2>
        {/* This links to /users/:id - the current route */}
        <Link to=".">User Profile</Link>
      </h2>

      <h2>
        {/* This links to /users/mj - a "sibling" route */}
        <Link to="../mj">MJ</Link>
      </h2>
    </div>
  );
}
  •  path 通配符将只支持 * 和 :(以前的?等将不再支持) 

// 这里直接拿了官网的例子,让我们看下 * 的作用(子孙路由)
import {
  BrowserRouter,
  Routes,
  Route,
  Link,
} from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="users/*" element={<Users />} />
      </Routes>
    </BrowserRouter>
  );
}

function Users() {
  return (
    <div>
      <nav>
        // path: user/me
        <Link to="me">My Profile</Link>
      </nav>

      <Routes>
        // path:  user/:id
        <Route path=":id" element={<UserProfile />} />

        // path:  user/me
        <Route path="me" element={<OwnUserProfile />} />
      </Routes>
    </div>
  );
}
  • 添加 useOutletContext 用于 路由之间共享状态

我们可以用 useOutletContext 在子路由与父路由之间共享一些值

function Parent() {
  const [count, setCount] = React.useState(0);
  return <Outlet context={[count, setCount]} />;
}


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

function Child() {
  const [count, setCount] = useOutletContext();
  const increment = () => setCount((c) => c + 1);
  return <button onClick={increment}>{count}</button>;
}

有关react-router-dom V6的更多相关文章

  1. ruby-on-rails - Ruby 长时间运行的进程对队列事件使用react - 2

    我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby​​脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几

  2. ruby - 单个 EventMachine react 器中的多个服务器 - 2

    是否可以在单个事件机器中运行多个服务器?我的意思是,多个服务可以由一个客户端连接同时使用。例如,登录服务器对用户进行身份验证,然后用户可以同时使用聊天室和简单的游戏,例如带有单个客户端套接字的跳棋?或者我是否需要为每个服务使用多个事件机器react器? 最佳答案 我试过了,它正在工作:#!/usr/bin/envrubyrequire'eventmachine'moduleEchoServerdefpost_initputs"--someoneconnectedtotheechoserver!"enddefreceive_datad

  3. React通过classnames库添加类 - 2

    React添加Class的方式在vue中添加class是一件非常简单的事情:你可以通过传入一个对象,通过布尔值决定是否添加类:button:class="{active:isFlag,aaa:true}">按钮button>你也可以传入一个数组:h2:class="['aaa','bbb']">HelloVueh2>h2:class="[className1,className2]">HelloVueh2>甚至是对象和数组混合使用:h2:class="['aaa',{active:isFlag}]">HelloVueh2>而在React中就相对繁琐了,React在JSX给了我们开发者足够多的灵

  4. 如何使React Router V4路由与React Transition Group(低级API)一起使用 - 2

    从ReactRouterV3过渡到V4后,我再也无法使ReactTransition组低级API工作。React路由器的文档显示了与CSS动画相关的高级API的示例,这些示例与低水平的JS风味不起作用。任何人都设法或知道让这个工作?看答案已经一个月了,所以我想您找到了自己的出路,但可能会对他人有所帮助。我创建了这个:https://www.npmjs.com/package/reeact-router-v4-transition在我遇到同样的问题之后。它在开关组件中提供了一种过渡组。从将开关更改为TransitionSwitch的Appart,它不需要大幅度更改。我将在接下来的几天(可能是星期

  5. javascript - 使用 React-Router 在路由之间传递 props - 2

    是在React-Router(1.0.0-rc)url参数中的路由之间传递数据的唯一方法吗?我有一个组件A,它使用Historymixin,并且有一个事件处理程序,该事件处理程序发出服务器请求,然后调用that.history.pushState(null,'/B');以过渡到路由B由组件B处理。现在,我想将服务器返回的一些数据作为Prop(例如“登录成功”)传递给组件B,或者以某种方式影响B的状态,但我找不到任何说明这是可能的。有什么办法可以做到这一点,还是我需要将其作为url参数传递? 最佳答案 你有两个选择:将数据作为查询参数

  6. javascript - react : input validation - 2

    我最近开始使用React,我遇到了输入验证问题。例如,它只是通过指令在另一个框架中作为Angular.js实现。经过一番研究,我发现newforms库,看起来像是当前开箱即用的最佳解决方案。但它非常重,不确定当前是否支持它(最后一次更新是7个月前)。另一种方法是将事件从父表单发送到其子输入,并在每个子输入上调用验证方法。但我找不到每个人都试图发明自己的东西的最佳实践,因此你需要自己写一些东西。表单验证的最佳解决方案是什么?React架构/框架(Flux/Redux)是否提供任何解决方案?谢谢, 最佳答案 我最近在React中使用了一

  7. javascript - 在单击事件上运行 AJAX 调用 - 使用 React.js - 2

    我正在创建一个网络应用程序,该应用程序将根据用户点击的城市对OpenWeatherAPI进行AJAX调用以获取城市的天气数据。我的前端使用React,后端使用Node.js/Express-但我无法正确设置如何根据用户的点击进行API调用。如何重构我的代码以使其基于点击?这是我目前所拥有的(JSBIN:http://bit.ly/1WedsL2)——目前硬编码为“London”:vardata=[{name:"London"},{name:"Tokyo"},{name:"NYC"}];varMusicBox=React.createClass({render:function(){re

  8. javascript - 在 React Native 中查看组件层次结构 - 2

    调试React网站时,我可以使用ReactDeveloperTools查看组件层次结构:我如何在ReactNative中做同样的事情?rageshake菜单包含一个“检查器”,但它似乎只能让我通过点击它来检查单个元素-我看不到任何浏览完整组件层次结构的方法。 最佳答案 不幸的是,从react-native0.12版本开始,Devtools的“React”选项卡不再起作用。这是aknownissue.有一个quiteactivediscussiononGithub已经开放了一段时间,但还没有解决方案。更新Devtools“React”

  9. javascript - 在 React.JS 中禁用右键单击 - 2

    如何在ReactJS中禁用Canvas中的右键单击。这是我尝试过但仍然无效的方法:letCanvas={e.preventDefault();returnfalse;}}height={500}width={500}ref="canvas"/>;浏览器控制台中也会显示警告。Warning:Returningfalsefromaneventhandlerisdeprecatedandwillbeignoredinafuturerelease.Instead,manuallycalle.stopPropagation()ore.preventDefault(),asappropriate.

  10. javascript - react 路由器中的层次结构 - 2

    我正在学习React,我尝试创建一些路由,我的入口点上有这段代码:importReactfrom'react';importReactDOMfrom'react-dom';import{Router,Route,IndexRoute,Link,IndexLink,browserHistory}from'react-router';importAppfrom'./app/Components/AppComponent';importSupervisoryReportfrom'./app/Components/SupervisoryReportComponent';importTopmen

随机推荐