前面我們有稍微提到 Link
,但是我們並沒有很認真的去認識它,只是單純帶到如何使用而已,所以這一篇會特別去說明 Link
,同時也會介紹到另一個東西,也就是 NavLink
哩。
雖然前面一篇章節有使用到 Link
但僅僅使用它的 to
屬性,但是 Link
有很多屬性可以使用,這邊我們就來看看它有哪些屬性可以使用。
首先 Link
的基礎寫法是以下
<Link to="/">Home</Link>
而其實 to
屬性可以接受兩個東西,最基本的是 String (字串),這也是最基礎的寫法,另一個則是 Object,而 Object 可以接受的屬性有以下幾個
<Link to={{
pathname: '/',
search: '?q=ray',
hash: '#app',
state: {
abc: true,
}
}}>Home</Link>
這個 Object 代表著 window.location
屬性,主要包含以下
pathname
search
hash
state
基本上 pathname
比較沒有什麼太大問題,就是與原本寫單純的 to
字串路徑是一樣的效果,而 search
、hash
這兩個屬性當你有撰寫時,點擊後 Url 則會呈現以下效果
http://example/#/?q=ray#app
但是裡面比較特別的是 state
,state
可以用於傳遞資料用的一個方式,但要注意一件很重要的事情,也就是 React Router V6 之後 state
不再是寫在 to
裡面,而是寫在外面
<Link to={{
pathname: '/products',
}}
state={{
products: {
id: '1',
name: 'QQ 產品'
}
}}>
產品詳細
</Link>
透過 state
的參數在切換頁面時,就可以將前一頁面的資料往下一頁面傳遞,接著透過以下方式就可以取得 state
的資料
const { state } = useLocation();
useEffect(() => {
console.log(state); // { products: { id: '1', name: 'QQ 產品' } }
},[]);
有沒有超簡單的~
那麼為了避免太過混淆,所以這邊我將範例程式碼單純化放在這邊。
接下來要介紹另一個切換頁面的方式,也就是 <NavLink />
,而 <NavLink />
其實簡單來講就是進階版的 <Link />
,為什麼這樣說呢?因為它可以追蹤你當前的頁面並給予相對應的狀態,因此這對於製作導航列連結時非常的好用,首先先來看一下 <NavLink />
基本寫法
<NavLink to="/">Home</NavLink>
那什麼是追蹤頁面並給予相對應狀態呢?這邊這邊先挪用一下 ToDoList 所製作的導航列,這邊先將 Link
通通改成 NavLink
,這邊會需要使用 ToDoList 所製作的導航列主要是為了方便展示而已,所以目前 main.jsx 程式碼如下
import React from 'react'
import { HashRouter, NavLink, Routes, Route } from "react-router-dom";
import ReactDOM from 'react-dom/client'
import App from './App'
import ToDoList from './ToDoList'
import Products from './Products'
import Admin from './Admin'
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<HashRouter>
<nav className="px-5 flex items-center h-[60px] bg-indigo-500 text-white">
<h1 className="mr-auto text-2xl">React TodoList</h1>
<ul className="flex">
<li className="mr-3">
<NavLink to="/home" className="border p-3 hover:bg-indigo-600 duration-500"
>Home</NavLink>
</li>
<li className="mr-3">
<NavLink to="/todolist" className="border p-3 hover:bg-indigo-600 duration-500">ToDoList</NavLink>
</li>
<li className="mr-3">
<NavLink to='/products'
className="border p-3 hover:bg-indigo-600 duration-500"
>產品詳細</NavLink>
</li>
<li className="mr-3">
<NavLink to='/admin'
className="border p-3 hover:bg-indigo-600 duration-500"
>Admin</NavLink>
</li>
</ul>
</nav>
<Routes>
<Route path="/" element={ <App /> } />
<Route path="/todolist" element={ <ToDoList /> } />
<Route path="/products" element={ <Products /> } />
<Route path="/admin" element={ <Admin /> } />
</Routes>
</HashRouter>
</React.StrictMode>
)
接下來你可以打開瀏覽器查看網頁元素找到當前頁面的 a
連結,你會發現 class 多了一個 active
,而這個 active
代表你當前在這個頁面
當你切換頁面時,這個 action
也會自動切換
因此透過這個方式,我們可以大大優化使用者體驗,讓使用者透過導覽列就知道它當前在哪個頁面。
如果你想自定義的 active
樣式名稱,例如改成 router-link-active
的話,則可以這樣子調整
<NavLink
to="/"
className={({ isActive }) => isActive ? 'router-link-active' : null }
>
Home
</NavLink>
那這個時候會發生一個問題,就是我們原本所寫的 NavLink
上面已經有 className
了
<NavLink
to="/"
className="border p-3 hover:bg-indigo-600 duration-500"
>
Home
</NavLink>
如果你再補一個 className={({ isActive }) => isActive ? 'router-link-active' : null }
就會出現這個錯誤 warning: Duplicate key "className" in object literal
。
那麼該怎麼解決呢?如果想要同時兩者具備的話,你必須改成以下
<NavLink
to="/"
className={({ isActive }) =>
[
'border p-3 hover:bg-indigo-600 duration-500',
isActive ? 'router-link-active' : null
].join(' ')
}
>
Home
</NavLink>
這樣子你就可以正常同時擁有樣式跟判斷 active
狀態的樣式,而這邊我也補一下 router-link-active
啟用時的樣式,請在 index.css 裡面加入以下
.router-link-active {
@apply bg-indigo-800;
}
透過這個方式就可以做到追蹤導航給予 router-link-active
樣式
那麼額外科普一下有些人可能會查到 NavLink
可以使用 activeClassName
改變 active
的樣式名稱,但是其實後來 React Router 6 之後就棄用 activeClassName
這個屬性了,所以如果你在使用 activeClassName
這個屬性的話,就會出現這個錯誤以下這個錯誤
Warning: React does not recognize the
activeClassName
prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercaseactiveclassname
instead. If you accidentally passed it from a parent component, remove it from the DOM element.
那麼這邊範例程式碼也都放在這邊唷。
本文將會同步更新到我的部落格