首頁 > 軟體

react-router-dom v6 使用詳細範例

2022-09-12 18:00:34

一、基本使用

首先安裝依賴:

npm i react-router-dom

引入實現路由所需的元件,以及頁面元件:

import { BrowserRouter, Routes, Route } from "react-router-dom";
import Foo from "./Foo";
import Bar from "./Bar";
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/foo" element={<Foo />} />
        <Route path="/bar" element={<Bar />} />
      </Routes>
    </BrowserRouter>
  );
}
  • path:路徑
  • element:要渲染的元件

注意BrowserRouter元件最好放在最頂層所有元件之外,這樣能確保內部元件使用 Link 做路由跳轉時不出錯

二、路由跳轉

在跳轉路由時,如果路徑是/開頭的則是絕對路由,否則為相對路由,即相對於當前 URL進行改變

2.1 Link 元件

Link元件只能在Router內部使用,因此使用到Link元件的元件一定要放在頂層的 Router 之內

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

<Link to="foo">to foo</Link>;

2.2 NavLink 元件

  • NavLink元件Link元件的功能是一致的,區別在於可以判斷其to屬性是否是當前匹配到的路由
  • NavLink元件styleclassName可以接收一個函數,函數接收一個含有isActive欄位的物件為引數,可根據該引數調整樣式
import { NavLink } from "react-router-dom";

function Foo() {
  return (
    <NavLink style={({ isActive }) => ({ color: isActive ? "red" : "#fff" })}>
      Click here
    </NavLink>
  );
}

2.3 程式設計式跳轉

使用useNavigate勾點函數生成navigate函數,可以通過 JS 程式碼完成路由跳轉

useNavigate取代了原先版本中的useHistory

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

function Foo(){
    const navigate = useNavigate();
    return (
        // 上一個路徑:/a;    當前路徑: /a/a1
        <div onClick={() => navigate('/b')}>跳轉到/b</div>
        <div onClick={() => navigate('a11')}>跳轉到/a/a1/a11</div>
        <div onClick={() => navigate('../a2')}>跳轉到/a/a2</div>
        <div onClick={() => navigate(-1)}>跳轉到/a</div>
    )
}
  • 可以直接傳入要跳轉的目標路由(可以使用相對路徑,語法和 JS 相同)
  • 傳入-1表示後退

三、動態路由引數

3.1 路徑引數

  • Route元件中的path屬性中定義路徑引數
  • 在元件內通過useParams hook 存取路徑引數
<BrowserRouter>
  <Routes>
    <Route path="/foo/:id" element={<Foo />} />
  </Routes>
</BrowserRouter>;

import { useParams } from "react-router-dom";
export default function Foo() {
  const params = useParams();
  return (
    <div>
      <h1>{params.id}</h1>
    </div>
  );
}

路徑匹配規則

當URL同時匹配到含有路徑引數的路徑和無引數路徑時,有限匹配沒有引數的”具體的“(specific)路徑。

<Route path="teams/:teamId" element={<Team />} />
<Route path="teams/new" element={<NewTeamForm />} />

如上的兩個路徑,將會匹配 teams/new 。

路徑的正則匹配已被移除。

相容類元件

在以前版本中,元件的props會包含一個match物件,在其中可以取到路徑引數。

但在最新的 6.x 版本中,無法從 props 獲取引數。

並且,針對類元件的 withRouter 高階元件已被移除。因此對於類元件來說,使用引數有兩種相容方法:

  • 將類元件改寫為函陣列件
  • 自己寫一個 HOC 來包裹類元件,用 useParams 獲取引數後通過 props 傳入原本的類元件

3.2 search 引數

  • 查詢引數不需要在路由中定義
  • 使用 useSearchParams hook 來存取和修改查詢引數。其用法和 useState 類似,會返回當前物件和更改它的方法
  • 使用 setSearchParams 時,必須傳入所有的查詢引數,否則會覆蓋已有引數
import { useSearchParams } from "react-router-dom";

// 當前路徑為 /foo?id=12
function Foo() {
  const [searchParams, setSearchParams] = useSearchParams();
  console.log(searchParams.get("id")); // 12
  setSearchParams({
    name: "foo",
  }); // /foo?name=foo
  return <div>foo</div>;
}

四、巢狀路由

5.1 路由定義

通過巢狀的書寫Route元件實現對巢狀路由的定義。

path 開頭為 / 的為絕對路徑,反之為相對路徑。

<Routes>
  <Route path="/" element={<Home />}></Route>
  <Route path="/father" element={<Father />}>
    <Route path="child" element={<Child />}></Route>
    <Route path=":name" element={<Another />}></Route>
  </Route>
</Routes>

5.2 在父元件中展示

在父元件中使用Outlet來顯示匹配到的子元件

import { Outlet } from "react-router-dom";
function Father() {
  return (
    <div>
      // ... 自己元件的內容 // 留給子元件Child的出口
      <Outlet />
    </div>
  );
}

5.3 在元件中定義

可以在任何元件中使用 Routes 元件,且元件內的Routes中,路徑預設帶上當前元件的路徑作為字首。

注意:此時定義父元件的路由時,要在後面加上 /* ,否則父元件將無法渲染。

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="dashboard/*" element={<Dashboard />} />
</Routes>
function Dashboard() {
  return (
    <div>
      <p>Look, more routes!</p>
      <Routes>
        <Route path="/" element={<DashboardGraphs />} />
        <Route path="invoices" element={<InvoiceList />} />
      </Routes>
    </div>
  );
}

五、預設路由

定義: 在巢狀路由中,如果 URL 僅匹配了父級 URL,則Outlet中會顯示帶有index屬性的子路由。可以使用在路由的任何層級

<Routes>
  <Route path="/foo" element={Foo}>
    <Route index element={Default}></Route>
    <Route path="bar" element={Bar}></Route>
  </Route>
</Routes>
  • 當 url 為/foo時:Foo 中的 Outlet 會顯示 Default 元件
  • 當 url 為/foo/bar時:Foo 中的 Outlet 會顯示為 Bar 元件

六、全匹配路由

定義:  path屬性取值為*時,可以匹配任何(非空)路徑,該匹配擁有最低的優先順序。可以用於設定 404 頁面。

<Routes>
  <Route path="/foo" element={Foo}>
    <Route path="bar" element={Bar}></Route>
    <Route path="*" element={NotFound}></Route>
  </Route>
</Routes>

七、多組路由

通常,一個應用中只有一個Routes元件。

但根據實際需要也可以定義多個路由出口(如:側邊欄和主頁面都要隨 URL 而變化)

<Router>
  <SideBar>
    <Routes>
      <Route></Route>
    </Routes>
  </SideBar>
  <Main>
    <Routes>
      <Route></Route>
    </Routes>
  </Main>
</Router>

八、路由重定向

當在某個路徑/a下,要重定向到路徑/b時,可以通過Navigate元件進行重定向到其他路徑

等價於以前版本中的Redirect元件

import { Navigate } from "react-router-dom";
function A() {
  return <Navigate to="/b" />;
}

九、佈局路由

當多個路由有共同的父級元件時,可以將父元件提取為一個沒有 path 和 index 屬性的Route元件(Layout Route)

<Route element={<PageLayout />}>
    <Route path="/privacy" element={<Privacy />} />
    <Route path="/tos" element={<Tos />} />
  </Route>

這種寫法等價於:

<Route
  path="/privacy"
  element={
    <PageLayout>
      <Privacy />
    </PageLayout>
  }
/>
<Route
  path="/tos"
  element={
    <PageLayout>
      <Tos />
    </PageLayout>
  }
/>

十、訂閱和操作 history stack的原理

瀏覽器會記錄導航堆疊,以實現瀏覽器中的前進後退功能。在傳統的前端專案中,URL的改變意味著向伺服器重新請求資料。

在現在的使用者端路由( client side routing )中,可以做到程式設計控制URL改變後的反應。如在點選a標籤的回撥函數中使用 event.preventDefault() 阻止預設事件,此時URL的改變不會帶來任何UI上的更新。

<a
  href="/contact" rel="external nofollow" 
  onClick={(event) => {
    // stop the browser from changing the URL and requesting the new document
    event.preventDefault();
    // push an entry into the browser history stack and change the URL
    window.history.pushState({}, undefined, "/contact");
  }}
/>

10.1 History物件

瀏覽器沒有直接提供監聽URL改變(push、pop、replace)的介面,因此 react-router 對原生的 history 對線進行了包裝,提供了監聽URL改變的API。

let history = createBrowserHistory();
history.listen(({ location, action }) => {
  // this is called whenever new locations come in
  // the action is POP, PUSH, or REPLACE
});

使用 react-router 時不需操作History物件(Routes 元件會進行操作)

11.2 Location物件

react-router 對 window.location 進行包裝後,提供了一個形式簡潔的Location物件,形如:

{
  pathname: "/bbq/pig-pickins",     // 主機名之後的URL地址
  search: "?campaign=instagram",    // 查詢引數
  hash: "#menu",                    // 雜湊值,用於確定頁面捲動的具體位置
  state: null,                      // 對於 window.history.state 的包裝
  key: "aefz24ie"                   // 
}

state

不顯示在頁面上,不會引起重新整理,只由開發人員操作。

可用於記錄使用者的跳轉詳情(從哪跳到當前頁面)或在跳轉時攜帶資訊。

可以用在 Link 元件或 navigate 方法中

&lt;Link to="/pins/123" state={{ fromDashboard: true }} /&gt;
let navigate = useNavigate();
navigate("/users/123", { state: partialUser });
複製程式碼

在目標的元件中,可以用 useLocation 方法獲取該物件

let location = useLocation();
console.log(location.state);

state中的資訊會進行序列化,因此如日期物件等資訊會變為string

key

每個Location物件擁有一個唯一的key,可以據此來實現基於Location的捲動管理,或是資料快取。

如:將 location.key 和 URL 作為鍵,每次請求資料前,先查詢快取是否存在來判斷是否實際傳送請求,來實現使用者端資料快取。

十一、 各類Router元件

11.1 HashRouter和BrowserRouter的區別

  • HashRouter 只會修改URL中的雜湊值部分;而 BrowserRouter 修改的是URL本身
  • HashRouter 是純前端路由,可以通過輸入URL直接存取;使用時 BrowserRouter 直接輸入URL會顯示404,除非設定Nginx將請求指向對應的HTML檔案。初次進入 / 路徑時或點選 Link 元件跳轉時不會傳送請求

11.2 unstable_HistoryRouter

使用 unstable_HistoryRouter 需要傳入一個 history 庫的範例,這將允許在非react作用於下操作history物件。

由於專案使用的history和react-router中使用的history版本可能不一樣,該API目前標為unstable狀態

11.3 MemoryRouter

HashRouter 和 BrowserRouter 都是依據外部物件(history)進行導航,而 MemoryRouter 則是自己儲存和管理狀態堆疊,多用於測試場景。

11.4 NativeRouter

推薦的用於 React Native的Router元件

11.5 StaticRouter

在nodejs端使用,渲染react應用。

import * as React from "react";
import * as ReactDOMServer from "react-dom/server";
import { StaticRouter } from "react-router-dom/server";
import http from "http";

function requestHandler(req, res) {
  let html = ReactDOMServer.renderToString(
    <StaticRouter location={req.url}>
      {/* The rest of your app goes here */}
    </StaticRouter>
  );

  res.write(html);
  res.end();
}

http.createServer(requestHandler).listen(3000);

十二、使用JS物件定義路由:useRoutes

使用 useRoutes hook,可以使用一個JS物件而不是Routes元件與Route元件來定義路由。其功能類似於react-router-config

useRoutes 的返回是 React Element,或是 null。

對於傳入的設定物件, 其型別定義如下:

interface RouteObject {
    caseSensitive?: boolean;
    children?: RouteObject[];
    element?: React.ReactNode;
    index?: boolean;
    path?: string;
}

到此這篇關於react-router-dom v6 使用詳細範例的文章就介紹到這了,更多相關react-router-dom v6 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com