React-router
是 react js
中路由的標準庫。它允許 React
應用程式的使用者在應用程式的不同部分(元件)之間移動。
react-router
團隊 宣佈將 在 2021 年底釋出react-router 版本 6 (v6)
的穩定版本,但由於一些重大的 API 更改,從 react-router
版本 5 (v5)
切換到 v6
可能會很困難. 在本文中,我們將介紹 v6 中的新功能以及如何將現有的 React 專案從 v5 升級到 v6。
要在我們的應用程式中升級 react-router
包的版本,我們導航到專案資料夾並執行
npm install react-router-dom@[VERSION_NUMBER]
替換VERSION_NUMBER
為我們要安裝的版本,或者如果我們想要最新版本,則替換為“ latest ”,如下所示:
npm install react-router-dom@6
或者
npm install react-router-dom@latest
請注意,我們必須連線到網際網路才能完成安裝,否則安裝將失敗。另外,請確保專案中的 react 版本是 v16.8 或更高版本
,因為 react-router v6
嚴重依賴於 react v16.8
最初支援的鉤子
Switch 被替換為 Routes
v5
時代的第一個被替代的是Switch元件
。該Switch
元件用於包裝我們的路由,它確保每次只載入一個匹配的路由。但這在 v6 中不再存在。我們使用Routes
元件來替換Switch
。請注意,我們仍然需要匯入BrowserRouter
包裝我們的應用程式,就像在 v5 中所做的那樣。
在 v5 中,我們是這樣做:
import { BrowserRouter, Switch } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<div className="App">
<Switch>
{" "}
{/* 路由Route在此定義 */}
</Switch>
</div>
</BrowserRouter>
);
}
export default App
但在 v6 中,我們將這樣做
import { BrowserRouter, Routes } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<div className="App">
<Routes>
{" "}
{/* Switch 會被改成 Routes */}
{/* 路由Route在此定義 */}
</Routes>
</div>
</BrowserRouter>
);
}
export default App
Route元件使用更新
儘管該Route元件在 v6
中仍然保留一個位置,但我們定義它的使用方式與我們在 v5
中的方式不同。我們將不再以 v5
中的任何方式放置我們想要渲染的元件,而是統一將其作為element
prop的值傳遞。
沒有exact配置
在 v5
中,不新增exact
作為Route元件
的props
的話,如果 URL 以 path 關鍵字開頭,則路徑將匹配,因為匹配過程是從上到下的順序。但在 v6 中,我們將不再需要該exact
配置,因為路徑模式匹配演算法已更改,並且現在更加增強。
在 v5 中,我們這樣做了:
<Switch>
{/* 三種Route元件使用定義 */}
<Route path="/signup" component={Product} />
{/* 或 */}
{/* 這個方法允許我們將 props 傳遞給渲染的元件 */}
<Route path="/games">
<Product id={2} />
</Route>
{/* 或是通過render函式 */}
<Route path="/games" render={(props) => <Product {...props} />} />
</Switch>
在 v6 中,
<Routes>
{" "}
<Route path="/games" element={<Product />} />
{/* 帶有props的渲染元件 */}
<Route path="/movies" element={<Product id={200} category="shirt" />} />
</Routes>
Links 和 NavLinks
Link
和NavLink
元件仍然可以執行在V6。Link
元件使用與在 v5 的時候保持一樣,但使用NavLink
元件時,刪除了activeClassName
和activeStyle
prop。在 v5 中,activeClassName
prop 用於在連結啟用後自動將一些 CSS
類應用於連結,同時activeStyle
允許我們在連結啟用時向連結新增內部樣式。
但是在 v6 中,我們現在可以使用一個函式來獲取有關連結活動狀態的資訊。該函式的引數是一個具有屬性的物件isActive
。此屬性在連結處於活動狀態時為真,在非活動時為假。isActive
的值允許我們使用條件表示式來指示活動樣式或類名。
在 v5 中,我們這樣做了:
import {NavLink} from “react-router-dom”
{/* … */}
<NavLink
to="/product"
style={{ color: "#689" }}
activeStyle={{ color: "#3072c9" }}
className="nav_link"
activeClassName="active"
>
Products
</NavLink>
但在 v6 中,我們將這樣做:
<NavLink
to="/product"
style={({ isActive }) => ({ color: isActive ? "#3072c9" : "#689" })}
className={({ isActive }) => `link${isActive ? " active" : ""}`}
>
Product
</NavLink>
Navigate替代Redirect
在 v5 中,我們使用該Redirect
元件將一個頁面帶到另一個頁面,但它不再從 v6
中的 react-router-dom
匯出。它已被Navigate
元件替換。
在 v5 中,我們這樣做了:
<Route path="/faq">
<Redirect to="/about" />
</Route>
<Route path="/about" component={About} />
但在 v6 中,我們將這樣做:
<Route path="/games" element={<Navigate to="/about" />} />;
<Route path="/games" element={<About />} />;
需要注意的是,如果我們只是按照Navigate上面程式碼片段中的方式新增元件,它只會將導航到該路徑的導航推送到導航堆疊中,但是如果我們打算用新頁面替換當前頁面,我們將 replace 屬性新增到Navigate元件中,如下所示:
<Route path="/games" element={<Navigate replace to="/about" />} />;
巢狀路由
顧名思義,巢狀路由是放置在另一個路由中的路由。它們用於在子元件中呈現更具體的資訊。在 v6 中,我們將巢狀路由放置為父路由的子路由。然後我們引入Outlet
元件,它是從渲染元件中的 react-router-dom
匯出的,用於指定我們希望巢狀資訊顯示在哪裡。Outlet
元件不是必需的,但它使程式碼更清晰。
在 v5 中,我們這樣做了:
import { useRouteMatch } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/about" component={About} />
<Route path="/product" component={Product} />
</Switch>
</BrowserRouter>
);
}
function Product() {
let match = useRouteMatch();
return (
<div>
<Switch>
{/* match.path 返回父路由中指定的路徑。在這種情況下,它是“/product" */}
<Route path={`${match.path}`}>
<AllProducts />
</Route>
{/* 匹配 /product/:id */}
<Route path={`${match.path}/:id`}>
<ProductDetail />
</Route>
</Switch>
</div>
);
}
在 v6 中,我們這樣做:
import { Outlet } from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/about" element={<About />} />
<Route path="/product" element={<Product />}>
{/* 這裡巢狀路由的路徑是相對於父路由的路徑的。 */}
{/* 這裡變成 "/product/" */}
<Route path="/" element={<AllProducts />} />
{/* 這裡變成 "/product/:id" */}
<Route path="/:id" element={<ProductDetail />} />
</Route>
</Routes>
);
}
function Product() {
return (
<Container>
<>
<div>Product</div>
{/* 父元件的其他內容 */}
</>
{/* 這是巢狀資訊開始的地方 */}
<Outlet />
</Container>
);
}
程式化導航
當使用者因路徑上發生的事件(例如單擊按鈕、API 請求完成等)而被重定向時,就會發生程式化導航。在 v5 中,我們可以使用useHistory
鉤子來執行以下操作:
import { useHistory } from "react-router-dom";
function Product() {
const history = useHistory();
const handleClick = () => {
//這會將新路線推送到導航堆疊的頂部
history.push("/new-route");
//這會將當前路線替換為導航堆疊中的新路由
history.replace("/new-route");
};
return (
<div>
<button>點選我重定向到新路由</button>
</div>
);
}
但是在 v6 中,useHistory
hook 被替換為useNavigate
hook,並且我們以不同的方式使用它。
import { useNavigate } from "react-router-dom";
function Product() {
const navigate = useNavigate();
const handleClick = () => {
//這會將新路線推送到導航堆疊的頂部
navigate("/new-route");
//這會將當前路線替換為導航堆疊中的新路由
navigate("/new-route", { replace: true });
};
return (
<div>
<button>點選我重定向到新路由</button>
</div>
);
}
一件很酷的事情是我們可以在導航堆疊上任意前進和後退。通過使用正數作為上述引數navigate()
,路由會向前移動該步數。負數向後做同樣的事情
// Goes forward
navigate(1)
// Goes forward twice
navigate(2)
// Goes backward
navigate(-1)
// Goes backward three times
navigate(-3)
刪除Prompt元件
Prompt如果有未儲存的更改,v5 中的元件可防止意外離開頁面。但是 react-router
團隊並沒有將它包含在 v6
中,也沒有替代方案。因此,如果你需要該功能,你可以手動實現它或返回到 v5。
除了不包括Prompt
在當前版本(v6)中,useBlocker
和usePrompt
都不起作用。react-router
團隊雖然在官方文件中表示,他們目前正在努力將其新增回 v6
,但不是針對 6.x 的第一個穩定版本。
概括
讓我們強調一下我們所經歷的變化。
- Switch 元件替換為 Routes 元件。
- 如何放置 Route 的渲染元件的更改。
- 路由中沒有exact。
- activeClassName和activeStyle不存在於NavLink元件了.
- 我們可以通過函式回撥訪問 NavLink 元件的 isActive 狀態。
- Redirect元件已替換為Navigate元件。
- 實現巢狀路由的一種更時尚的方式。
- 沒有Prompt元件
總之,如果你還沒有準備好從 v5 或任何其他版本切換到 v6,你可以繼續使用它安裝以前的版本。
npm install react-router-dom@[VERSION_NUMBER]
但是,你將錯過 v6 附帶的一些好東西,包括但不限於:
- 增強的路徑模式匹配演算法。
- 根據Bundlephobia,體積大小減少了 60%
我相信我們能夠成功地切換到 react-router v6 並停止使用 Switch 元件(雙關語非常有意)?。
擁有更出色的編碼體驗?。