iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

終究都要學 React 何不現在學呢?系列 第 27

終究都要學 React 何不現在學呢? - React Router - Hook - (27)

  • 分享至 

  • xImage
  •  

前言

那麼由於我們主要都是以 React Hook 為主,因此 React Router 也有提供一些 Hook 給我們使用,所以這邊我們也要稍微了解一下有哪些 React Router Hook 是常見的。

常用的 Hook

這邊我也簡單列出常用的 React Router Hook

  • useLocation
  • useParams
  • useNavigate
  • useRoutes

後面這邊也會簡單寫一些範例來認識上面的常用 Hook。

useLocation

前面章節我們已經有使用到 useLocation 來做一些事情,那麼它主要是幹嘛呢?

底下有一個我們前面所使用的 <Link> 範例,這邊我們可以看到 <Link> 有一個 to 的屬性,那麼這個 to 屬性就是我們要去的路徑跟參數

<Link to={{
    pathname: '/products',
    search: 'q=ray',
    hash: '#products',
  }}
  state={{
    products: {
      id: '1',
      name: 'QQ 產品'
    }
  }}>
  產品詳細
</Link>

而當我們若要取得 <Link> 裡面參數時,我們就可以使用 useLocation 來取的相關資訊,底下是一個簡單範例

import { useLocation } from "react-router";

const { hash, key, pathname, search, state } = useLocation();
  
useEffect(() => {
  console.log('hash:', hash); // hash: #products
  console.log('key:', key); // key: ry5x4mjc
  console.log('pathname:', pathname); // pathname: /products
  console.log('search:', search); // search: ?q=ray
  console.log('state:', state); // state: { products: { id: '1', name: 'QQ 產品' } }
},[]);

就算你改用 <NavLink> 來取代 <Link> 也是可以的,因為 <NavLink> 也是使用 useLocation 來取得相關資訊。

useParams

useParams 絕對是實戰上最常用的 React Router Hook,那它主要使用在哪裡呢?舉例一個情境,我們實戰上常常會有一個頁面是要顯示產品詳細資訊,那麼這個頁面的路徑就會是 /products/:id,而 :id 就是我們要取得的參數,所以我們就可以使用 useParams 來取得 :id 的參數,因此 Route 可以這樣寫

<Route path="/products" element={ <Products /> } >
  <Route path=":id" element={ <Product /> } />
</Route>

那麼為什麼會使用動態路由呢?因為我們不可能每個產品都要寫一個路徑,所以我們就可以使用動態路由來取得產品的 id,除此之外使用動態路由也有一個好處,當我們要分享產品給他人觀看時,我們就可以直接將產品的 id 丟到網址上,讓他人可以直接看到該產品的詳細資訊。

那麼如果要取得動態路由上的 :id 的話,就一定要使用 useParams

import { useParams } from "react-router";

const { id } = useParams();
  
useEffect(() => {
  console.log('params id:', id); // params id: 123
},[]);

透過 useParams 我們就可以輕鬆取得動態路由的 ID。

useNavigate

useNavigate 主要是用於重新導向,舉例來講當我們點了一個按鈕後,我們就可以使用 useNavigate 來重新導向到其他頁面,而底下範例就是重新導向到 /products/123 這個頁面

import { useNavigate } from "react-router";

const Products = () => {
  const navigate = useNavigate();

  return (
    <>
      <h1>Products</h1>
      <button
        className="border-1 bg-indigo-500 p-3 text-white"
        onClick={ () => navigate('/products/123')}
      >
        點我跳轉
      </button>
      <Outlet />
    </>
  )
}

export default Products;

當然也可以使用 useNavigate 來達到前一頁與後一頁

import { useNavigate } from "react-router";

const Products = () => {
  const navigate = useNavigate();

  return (
    <>
      <h1>Products</h1>
      <button
        className="border-1 bg-indigo-500 p-3 text-white"
        onClick={ () => navigate('/products/123')}
      >
        點我跳轉
      </button>
      <button
        className="border-1 bg-indigo-500 p-3 text-white"
        onClick={ () => navigate(-1) }
      >
        前一頁
      </button>
      <button
        className="border-1 bg-indigo-500 p-3 text-white"
        onClick={ () => navigate(1) }
      >
        後一頁
      </button>
      <Outlet />
    </>
  )
}

export default Products;

基本上就算你是傳入字串也是可以正常運作的 () => navigate('1')() => navigate('-1')

useRoutes

還記得我們前面 React Router 是如何建立的嗎?忘了也沒有關係,底下這邊也會附上範例

<HashRouter>
  <Routes>
    <Route path="/" element={ <App /> } >
      <Route path="todolist" element={ <ToDoList /> } />
    </Route>
    <Route path="/admin" element={ <Admin /> } >
      <Route path="products" element={ <AdminProducts /> } />
    </Route>
  </Routes>
</HashRouter>

相信有些人對於這種寫法不是很滿意,因為稍微有一點巢狀結構,而實戰上本身就會有很多巢狀結構,當結構過度巢狀時就會發生維護上的困擾,因此如果你不喜歡這種寫法的話,你可以使用 useRoutes 重新包裝。

那該如何使用 useRoutes 呢?首先這邊先建立一個專門管理 Router 的檔案,整體寫法會與你在使用 Vue Router 有 87% 神似,所以我這邊就將上方的範例改用 useRoutes 來寫

// router/index.js
import { useRoutes } from 'react-router-dom';

import App from '../App';
import ToDoList from "../TodoList";

import Admin from "../admin/Index";
import AdminProducts from "../admin/Products";


const routes = [
  {
    path: '/',
    element: <App />,
    children: [
      {
        path: '/todoList',
        element: <ToDoList />,
      },
    ],
  },
  {
    path: '/admin',
    element: <Admin />,
    children: [
      {
        path: 'products',
        element: <AdminProducts />,
      },
    ],
  }
];

export default () => useRoutes(routes);

接下來回到 main.jsx 將內容改成以下即可

import React from 'react'
import { HashRouter, Route, Routes, Link } from "react-router-dom";
import ReactDOM from 'react-dom/client'
import './index.css'

import Router from './router';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <HashRouter>
      <Router />
    </HashRouter>
  </React.StrictMode>
)

這樣子畫面就會如同前面相同,但整體程式碼卻也更簡潔,而且也非常神似 Vue Router 的寫法。

那麼這一篇差不多介紹到這邊,而這一篇就不提供範例了,讓你自己試著去實作看看哩。

後記

本文將會同步更新到我的部落格


上一篇
終究都要學 React 何不現在學呢? - React Router - Link 與 NavLink - (26)
下一篇
終究都要學 React 何不現在學呢? - React Router - Lazy Loading - (28)
系列文
終究都要學 React 何不現在學呢?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言