React-Router-dom V6 更新简单掌握


官方文档:react-router-dom
英文建议翻译

v6 与 v5 的区别

安装:
yarn add react-router-dom

npm install react-router-dom

react, react-router-dom 以及相关插件版本:

"dependencies": {
    "@testing-library/jest-dom": "^5.16.2",
    "@testing-library/react": "^12.1.3",
    "@testing-library/user-event": "^13.5.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^6.2.1",
    "react-scripts": "5.0.0",
    "web-vitals": "^2.1.4"
}

使用 React Router v6 在根组件下创建路由规则

import { BrowserRouter as Router } from 'react-router-dom';
import Demo from './pages/demo'
import './App.css';

function App() {
  return (
    <Router>
      <Demo />
    </Router>
  );
}

export default App;

HashRouter 使用的是 URL 的 hash 部分(即 window.location.hash),来保持页面的 UI 与 URL 的同步。
哈希历史记录不支持 location.key 或 location.state
BrowserRouter 使用 HTML5 的 history API(pushState, replaceState 和 popState),让页面的 UI 与 URL 同步。

HashRouter 和 BrowserRouter 的区别

URL 的表现形式不一样 BrowseRouter 使用 HTML5 的 history API,保证 UI 界面和 URL 同步。HashRouter 使用 URL 的哈希部分来保持 UI 和 URL 的同步。
哈希历史记录不支持 location.key 和 location.state。
HashRouter 不支持 location.state 和 location.key。
通过 state 的方式传值给下一个页面的时候,当到达新的页面,刷新或者后退之后再前进,BrowseRouter 传递的值依然可以得到。

上面是使用BrowserRouter模式,特点就是地址没有 # 号,也就说明地址需要经过特殊处理,不然可能刷新页面会404。

demo:

import { Route, Routes, NavLink } from "react-router-dom";
import One from "./one";
import Three from "./three";
import Two from "./two";
import NoFind from "./noFind";
export default function Demo() {
  return (
    <div>
      <h1 style={{ textAlign: "center" }}>我是标题</h1>
      <ul>
        <li>
          <NavLink to="/one">Go One</NavLink>
        </li>
        <li>
          <NavLink to="/two">Go Two</NavLink>
        </li>
        <li>
          <NavLink to="/three">Go Three</NavLink>
        </li>
      </ul>

      <hr />
      <Routes>
        <Route path="/one" element={One()} />
        <Route path="/two/*" element={Two()} />
        <Route path="/three" element={Three()} />
        <Route path="*" element={NoFind()} />
      </Routes>
    </div>
  );
}

因为之前在App中已经引入过路由规则,所以在demo组件中可以直接使用NavLink等Api,正常使用需要在BrowserRouter标签下。NavLink需要配置to属性,使用引号包裹路径。

在V6中去掉了原来的switch,改为了现在的Routes,而Route中也去掉了components,改为了功能更加强大的element,他可以包裹标签、组件等功能,不要忘了重要的404,必须配置路径为通配符,而且也是必须在最后一位上。

需要嵌套路由的Route上地址必须包括 ‘/*’ 以匹配子路由。

// two.js
import { Routes, Route, NavLink } from 'react-router-dom'
import Five from './five';
import Four from './four';
export default function Two() {
  return (
    <div>
      <h3>我是组件二</h3>
      <ul>
        <li>
          <NavLink to="/two/four">Go Two is four</NavLink>
        </li>
        <li>
          <NavLink to="/two/five">Go Two is five</NavLink>
        </li>
      </ul>
      <hr />
      <Routes>
        <Route path="/four" element={Four()} />
        <Route path="/five" element={Five()} />
      </Routes>
    </div>
  );
}
// four页面
import { Outlet } from 'react-router-dom'

export default function Four() {
  return (
    <div>    
      我是组件二的儿子Four
      <Outlet />
    </div>
  )
}

// five 页面
import { Outlet } from "react-router-dom";

export default function Five() {
  return (
    <div>
      我是组件二的儿子Five
      <Outlet />
    </div>
  );
}

值得一提的是对于模块来说,直接导入拼装和之前一样,都是如果是父页面进入子页面时必须要在子页面中添加Outlet这个占位件。

向路由组件传递params参数 :

import * as React from "react";
import {
  Route,
  Routes,
  NavLink,
  Link,
  BrowserRouter as Router,
  useParams,
  useLocation,
} from "react-router-dom";

const One = () => {
  const {id} = useParams();
  const handleClick = () => {
    console.log('时间戳', id);
  };
  return (
    <div>
      我是组件one
      <button onClick={() => handleClick()}>o n e</button>
    </div>
  );
};
const Two = () => {
  const { state } = useLocation();
  const handleClick = () => {
    console.log("内容", state);
  };
  return (
    <div>
      我是组件Two<button onClick={() => handleClick()}>t w o</button>
    </div>
  );
};

const App = () => {
  const id = Date.now()
  const content = {
    timeId: Date.now(),
    txt: '我是标题'
  }
  return (
    <Router>
      <h3>我是标题</h3>
      <ul>
        <li>
          <Link to={`/one/${id}`}>11111</Link>
        </li>
        <li>
          <NavLink to={`/two`} state={{content: content, otherNum: {id: '9999', cut: '拿来了!'}}}>
            22222
          </NavLink>
        </li>
      </ul>
      <Routes path="/one/:id">
        <Route path="/one/:id" element={<One />} />
        <Route path="/two" element={<Two />} />
      </Routes>
    </Router>
  );
}

export default App;

useParams获取到的值必须是你在Route中指定的:

<Route path="/one/:id" element={<One />} />

 const {id} = useParams();  // 可以获取
 const {userId} = useParams();  // undefined

假如你要useLocation获取传参,必须将他们放在state中。

注: element中虽然可以使用函数,但是似乎会导致一些hook无法使用, 下图是我同事发给我的,我找了半天也没发现什么问题,最后将函数使用的方式改为标签就可正常获取。

import { Route, Routes, NavLink, useParams } from "react-router-dom";
import One from "./one";
import Three from "./three";
import Two from "./two";
export default function Demo() {
  return (
    <div>
      <h1 style={{ textAlign: "center" }}>我是标题</h1>
      <ul>
        <li>
          <NavLink to="/one/999">Go One</NavLink>
        </li>
      </ul>
      <hr />
      <Routes>
        <Route path="/one/:id" element={One()} />
      </Routes>
    </div>
  );
}
import { useParams } from "react-router-dom"


export default function One() {
  const { id } = useParams()
  return <div onClick={() => console.log(id)}>我是组件一</div>;
}

当然,你们应该会发现,V6完全是为函数组件开发而设计的,先不说无法在类组件中使用,现在你想在axios中拦截并让他跳回登录的操作也无法实现了,这肯定会导致一些业务兼容问题,所以我的推荐是,不要用V6,起码等他真正的稳定或开发者想好再用!


文章作者: tttcpw
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 tttcpw !
  目录