iT邦幫忙

0

React-Router-Dom v6版本 與 舊版的差異範例

  • 分享至 

  • xImage
  •  

在網路上查找相關文章的時候,發現很多用法已經淘汰了,所以就自己整理這篇來當作筆記。

現在react-router-dom v6 版本改了很多,例如:

  1. 不再支援在route內使用客製化component,也就是說無法直接引用Layout。
  2. 也不支援Switch,需要改用routes,並且改用"element"作為Component引入點。
  3. 如果要在使用Link的時候傳遞參數,正常的props是無法使用的 (我理解是這樣,不太確定是否正確),要改用state傳遞,而被呼叫的Component要使用useLocation來接。

以下將重大差異的部份個別列出。

1. this.props.match在DOM v6由useLocation、useParams取代

DOM v6之前

之前的定義: 在每一個Route判斷到網址的路徑相符,要渲染該組件時都會將物件match給傳進該組件中。

也因為以上特性,所以早期很多人寫法都是直接從match取得參數:

const NotePage = ({match}) => {
		let noteId = match.params.id
}

另外在DOM v6之前也有人使用match取得path:

import React from "react"
import { Route, Link } from "react-router-dom"

class About extends React.Component {
    render() {
        //在Route將組件渲染時,會傳入match物件,在這裡把它印出來
        console.log(this.props.match)
        return (
            <div>
                <h2>關於我們選單</h2>
                <ul>
                    {/*url是match的屬性之一,會回傳網址列的路徑*/}
                    <li><Link to={`${this.props.match**.url**}`}>理念介紹</Link></li>
                    <li><Link to={`${this.props.match.url}/his`}>歷史沿革</Link></li>
                </ul>
                {/*path也是match的屬性之一,會回傳透過哪個Route進入的path屬性*/}
                <Route exact path={`${this.props.match**.path**}`} component={Introd} />
                <Route path={`${this.props.match.path}/his`} component={His} />
            </div>
        )
    }
}

DOM v6之後

取得參數部分,由useParams取代,如下:

const NotePage = () => {
		let {id} = useParams();
}

如果要取得現在的URL,則變成是要用useLocation():

const location = useLocation();
console.log(location.pathname);

Here are the properties it returns:

  • The hash:  Returns the anchor part of the current page.
  • The pathname:  Returns the path of the current page.
  • The search:  Returns the query part of the current page.

2. Redirect Component在DOM v6中被Navigate Component取代

DOM v6之前

在DOM v5版本中我們可以使用Redirect Component強制轉導,

概念為:

class About extends React.Component {
    render() {
        return (
						<div>
                <Switch>
                    <Route exact path={`${this.props.match.path}`} component={Introd} />
                    <Route path={`${this.props.match.path}/his`} component={His} />
										//...
                    <Redirect from={`${this.props.match.path}/story`} to={`${this.props.match.url}/his`} />
                </Switch>
            </div>
        )
    }
}

from意思是當目前的Link連結到${this.props.match.path}/story這個路徑的時候,Redirect會將網址重新轉到${this.props.match.url}/his上。

Redirect的to屬性具體如下:

<Redirect from={`${this.props.match.path}/story`} 
            to={{pathname:`${this.props.match.url}/his`
                ,search: "?hey=UCCU"
                ,state:{name:'Referrer'}}} />

DOM v6之後

React 是 React Router v6 中新引入的組件,其作用與已棄用的 組件相同。

我們可以使用導航組件聲明重定向,如下所示:

<Navigate to="/somewhere/else" />

鑑於我們希望在用戶訪問我們應用程序上的無效 URL 時將用戶重定向到 home 組件,我們可以這樣編寫導航代碼:

<Routes>
  <Route path='/' element={<h1>Home Page Component</h1>} />
  <Route path='/login' element={<h1>Login Page Component</h1>} />
    // New line
  <Route path='*' element={**<Navigate to='/' />**} />
</Routes>

3. useHistory在DOM v6中被useNavigate取代

DOM v6之前

useHistory 鉤子是React Router Dom v5中的一個函數,它使我們能夠訪問瀏覽器History Stack實例。

useHistory 可用於從當前位置 導航到新位置返回到特定位置

import { useHistory } from "react-router-dom";
import "./App.css";
 
function App() {
  const history = useHistory();
 
  const handleGoBack = () => {
    history.goBack();
  };
  return (
    <>
      <button onClick={handleGoBack}>Go Back</button>
    </>
  );
}
 
export default App;

從上面的代碼中,我們使用 useHistory hook中的 goBack() 方法來建立 回上一頁按鈕功能。

我們還可以使用 useHistory Hook重定向到新路徑,如下所示:

import { useHistory } from "react-router-dom";
import "./App.css";
 
function App() {
  const history = useHistory();
 
  const handleGoHome = () => {
     history.push("/home"); // New line 
  };
  return (
    <>
      <button onClick={handleGoHome}>Go Back</button>
    </>
  );
}
 
export default App;

DOM v6之後

useHistory 在 React Router v6 中也被棄用,取而代之的是 useNavigate。

useNavigate 允許我們在函數內以編程方式導航路徑,它採用與 組件相同的props,並且與 useHistory 具有相同的目的。

例如我們使用useNavigate()模擬用戶登錄時重定向到登錄頁面:

import { useEffect, useState } from "react";
import { Navigate, Route, Routes, useNavigate } from "react-router-dom";
import "./App.css";
 
function App() {
  const navigate = useNavigate();
  const [isLoggedIn, setisLoggedIn] = useState(false);
 
  useEffect(() => {
    // Checking if user is not loggedIn
    if (!isLoggedIn) {
      navigate("/");
    } else {
      navigate("/login");
    }
  }, [navigate, isLoggedIn]);
 
  return (
    <>
      <Routes>
        <Route path='/' element={<h1>Home Page Component</h1>} />
        <Route path='/login' element={<h1>Login Page Component</h1>} />
        <Route path='*' element={<Navigate to='/' />} />
      </Routes>
 
      {/* New line */}
      {isLoggedIn || (
        <button onClick={() => setisLoggedIn(true)}>Log me in</button>
      )}
    </>
  );
}
 
export default App;

如上範例,官方傾向於建議在useEffect()中使用useNavigate。

另外,由於能夠操作瀏覽器History Stack,因此也能做到重定向到上一頁:

import { useNavigate } from "react-router-dom";
import "./App.css";
 
function App() {
  const navigate = useNavigate();
 
  const handleGoBack = () => {
     navigate(-1); // new line
  };
  return (
    <>
      <button onClick={handleGoBack}>Go Back</button>
    </>
  );
}
 
export default App;

4. Link傳遞props參數問題

Pass props in Link react-router

上面這篇討論很多解法

但我自己試成功是使用官網範例:

https://reactrouter.com/en/6.8.0/components/link#state

The state property can be used to set a stateful value for the new location which is stored inside history state. This value can subsequently be accessed via useLocation().

<Link to="new-path" state={{ some: "value" }} />

You can access this state value while on the "new-path" route:

let { state } = useLocation();

5. 在Route中加入Layout的問題

In react-router-dom v6 there is no longer a use case/allowance for custom route components. Only Route (or Fragment) components can be children of the Routes component. The layout components are rendered on a Route component's element prop and they can render children components or Outlets if they are wrapping nested Route components.

Given a layout components rendering a children prop *:

const NoNavbarLayout = ({ children }) => (
  <div className="login-layout">
    <p>No navbar</p>
    {children}
  </div>
);

  • I am assuming the NavbarLayout component is similar

The routes would look as such:

<Routes>
  <Route
    path="/bossHome"
    element={(
      <NoNavbarLayout>
        <BossHomePage />
      </NoNavbarLayout>
    )}
  />
  <Route
    path="/home"
    element={(
      <NavbarLayout>
        <Home />
      </NavbarLayout>
    )}
  />
</Routes>

參考資料:
臨時找不到原本參考的那篇,找到了再補上來


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言