React?Router掌握路由搭建與權(quán)限管控的操作方法(?從入門到精通)
一、前言
react-router
庫在 React 應(yīng)用開發(fā)中扮演著至關(guān)重要的角色,它是實現(xiàn)頁面路由管理的核心工具,能夠讓開發(fā)者根據(jù)不同的 URL 路徑精準(zhǔn)地渲染對應(yīng)的組件,這對于構(gòu)建流暢、交互性強的單頁面應(yīng)用(SPA)來說不可或缺。通過它,用戶在瀏覽應(yīng)用時無需頻繁刷新整個頁面,就能實現(xiàn)頁面內(nèi)容的動態(tài)切換,極大地提升了用戶體驗。
例如,許多知名的 React 應(yīng)用,如一些大型的電商平臺前端、在線辦公軟件等,都借助 react-router
來管理繁多的頁面路由,實現(xiàn)復(fù)雜的功能模塊切換和頁面導(dǎo)航,使得用戶可以方便快捷地在各個功能頁面之間穿梭。
一般來說,React-Router v6 需要 React v16.8 或更高版本。因為 React-Router v6 利用了 React 的 Hooks 等特性,而 React v16.8 是第一個引入 Hooks 的版本。如果使用較低版本的 React,可能會導(dǎo)致 React-Router 無法正常工作或某些功能缺失。
二、安裝
- 使用 npm 安裝(推薦)
- 打開終端,進(jìn)入 React 項目目錄。
- 若沒安裝 React 項目,可用 Create React App 等創(chuàng)建新項目。
- 在項目目錄下,運行
npm install react-router-dom
命令,安裝成功后,可查看node_modules
目錄有無react-router-dom
文件夾,或在代碼文件導(dǎo)入相關(guān)模塊(如import { BrowserRouter } from'react-router-dom'
)驗證,無報錯即安裝正確。
使用 yarn 安裝
- 打開終端,進(jìn)入 React 項目目錄。
- 運行
yarn add react-router-dom
命令,完成后即可使用。
三、基礎(chǔ)使用
項目 React 版本: 18.3.1;react-router-dom 版本:7.1.1。
設(shè)置路由基礎(chǔ)結(jié)構(gòu)
在 React 應(yīng)用入口文件(通常是 index.js
或 main.js
),用 BrowserRouter
(基于瀏覽器歷史記錄,URL 更自然)或 HashRouter
(特殊部署需求或兼容舊瀏覽器)包裹整個應(yīng)用。如在 main.js
中:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter as Router } from 'react-router-dom'; import App from './App.jsx'; createRoot(document.getElementById('root')).render( <StrictMode> <Router> <App /> </Router> </StrictMode> );
這里將 App
組件包裹在 Router
(BrowserRouter
的別名)中,這樣 App
組件及其子組件就可以訪問到路由相關(guān)的功能。
定義路由和組件關(guān)聯(lián)
在 App
組件或其他組件內(nèi),用 Route
組件定義路由規(guī)則。
直接在組件中定義路由
這種方式將路由定義直接放在組件內(nèi)部,對于小型應(yīng)用或者路由規(guī)則比較簡單的情況,具有直觀的優(yōu)點。開發(fā)者可以一目了然地看到某個組件與具體路由路徑的關(guān)聯(lián)情況,并且路由規(guī)則與組件緊密結(jié)合,很適合組件自身內(nèi)部的路由管理,尤其當(dāng)組件是獨立的功能模塊時,能使模塊功能更加內(nèi)聚。
import React from 'react'; import { Route } from 'react-router-dom'; import Home from './Home'; import About from './About'; const App = () => { return ( <div> {/* Route 組件定義路由,exact 精確匹配,確保路徑完全是'/'才渲染 Home 組件, 訪問'/about'時不會渲染 Home 組件。訪問'/'渲染 Home 組件,訪問'/about'渲染 About 組件。 */} <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </div> ); } export default App
然而,當(dāng)應(yīng)用規(guī)模逐漸變大,路由規(guī)則變得復(fù)雜時,這種寫法會暴露出明顯的缺點。比如在一個大型電商應(yīng)用中,若有上百個路由都寫在 App 組件內(nèi),代碼會變得極為臃腫,查找特定路由關(guān)聯(lián)的組件、修改路由參數(shù)等維護(hù)操作將變得異常繁瑣,代碼的可讀性也會大打折扣,不利于后續(xù)的開發(fā)和維護(hù)。
定義單獨一個路由表
單獨創(chuàng)建一個路由表可以將所有的路由規(guī)則集中管理,這對于大型應(yīng)用開發(fā)來說尤為重要。在開發(fā)過程中,開發(fā)者能夠在一個文件中清晰地查看所有的路由路徑、對應(yīng)的組件以及可能的路由參數(shù)等關(guān)鍵信息。而且,路由表具備良好的復(fù)用性,比如在不同的布局組件(如具有不同側(cè)邊欄的布局)中,都可以引用這個統(tǒng)一的路由表來實現(xiàn)相同的路由功能,無需重復(fù)配置。同時,當(dāng)需要對路由規(guī)則進(jìn)行修改時,只需在路由表文件中操作即可,無需逐個在使用路由的組件中進(jìn)行修改,極大地提高了開發(fā)效率和代碼的可維護(hù)性。隨著應(yīng)用的不斷發(fā)展,添加新路由也十分方便,并且對于路由的中間件(如權(quán)限驗證,只有登錄用戶才能訪問某些路由)等功能,在路由表中也能更便捷地進(jìn)行配置。
創(chuàng)建 routes.js
文件定義路由表,集中管理路由規(guī)則。
import { lazy } from 'react'; // lazy 用于設(shè)置路由懶加載 const Home = lazy(() => import('@/pages/Home')); const About = lazy(() => import('@/pages/About')); const Router = [ { path: '/', element: <Home /> }, { path: '/about', element: <About /> }, // 設(shè)置 404 頁面 { path: '*', element: <NotFound /> } ]; export default Router
然后在 App 組件中使用這個路由表:
import router from './router'; import { Suspense } from 'react'; import { useRoutes } from 'react-router-dom'; function App() { // useRoutes 依傳入路由配置生成相應(yīng)路由元素,代表應(yīng)渲染組件樹結(jié)構(gòu)。 const element = useRoutes(router); // Suspense 設(shè)頁面跳轉(zhuǎn)加載提示,組件加載時顯示 fallback 指定內(nèi)容。 return <Suspense fallback={'loading...'}>{element}</Suspense>; } export default App
此方式適用于大型應(yīng)用,復(fù)用性好,修改路由便捷,還方便配置中間件(如權(quán)限驗證)。
創(chuàng)建導(dǎo)航鏈接
使用 Link 組件來創(chuàng)建應(yīng)用內(nèi)部的導(dǎo)航鏈接,它與傳統(tǒng)的 標(biāo)簽不同,當(dāng)用戶點擊 Link 組件時,不會引起整個頁面的刷新,而是通過 JavaScript 更新 URL 并觸發(fā)相應(yīng)的組件渲染,實現(xiàn)單頁面應(yīng)用內(nèi)的無縫導(dǎo)航。
import React from 'react'; import { Link } from 'react-router-dom'; const Navigation = () => { return ( <nav> {/* Link 組件 to 屬性指定導(dǎo)航目標(biāo)路徑,點擊'Home'鏈接導(dǎo)航到根路徑渲染 Home 組件, 點擊'About'鏈接導(dǎo)航到'/about'路徑渲染 About 組件。 */} <Link to="/">Home</Link> <Link to="/about">About</Link> </nav> ); } export default Navigation
四、核心組件和功能
BrowserRouter 和 HashRouter
- BrowserRouter:基于 HTML5 瀏覽器歷史記錄 API,URL 格式自然,無“#”符號,如電商產(chǎn)品詳情頁 URL 可為“/products/123”,利于 SEO。
- HashRouter:用 URL 哈希部分管理路由,適用于舊瀏覽器或服務(wù)器不支持 HTML5 歷史記錄 API 的情況,部署在簡單靜態(tài)服務(wù)器上表現(xiàn)良好。
Route 組件
Route
組件是核心,定義路由規(guī)則,關(guān)聯(lián) URL 路徑與組件。
import React from 'react'; import { Route, BrowserRouter as Router } from 'react-router-dom'; import Home from './Home'; import About from './About'; const App = () => { return ( <Router> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Router> ); } export default App
exact
屬性精確匹配路徑,避免誤渲染。
Link 組件
與傳統(tǒng) <a>
標(biāo)簽不同,點擊不刷新頁面,更新 URL 觸發(fā)組件渲染。
import React from 'react'; import { Link } from 'react-router-dom'; const Navigation = () => { return ( <nav> <Link to="/">Home</Link> <Link to="/about">About</Link> </nav> ); } export default Navigation
Switch 組件
包裹一組 Route
組件,只渲染第一個匹配成功的 Route
,防止多個組件同時渲染。
import React from 'react'; import { Route, Switch, BrowserRouter as Router } from 'react-router-dom'; import Home from './Home'; import About from './About'; import NotFound from './NotFound'; const App = () => { return ( <Router> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route component={NotFound} /> </Switch> </Router> ); } export default App
在這個例子中,如果沒有Switch組件,當(dāng)用戶訪問一個不存在的路徑時,NotFound組件和前面可能部分匹配的組件(比如Home組件)都可能會被渲染。有了Switch組件,只有NotFound組件會被渲染,因為前面的路由都沒有匹配成功
五、路由參數(shù)和嵌套路由
路由參數(shù)
React-Router
允許在路由路徑中定義參數(shù)。例如,在一個列表中,內(nèi)容詳情頁的路由可以定義為 /articles/:id
,其中 :id
是一個參數(shù),表示詳情的唯一標(biāo)識符。在組件中可以通過 props.match.params
獲取這個參數(shù)。
import React from 'react'; import { Route, BrowserRouter as Router } from 'react-router-dom'; const ArticleDetail = props => { const articleId = props.match.params.id; // 根據(jù) articleId 獲取文章詳情并渲染 return ( <div> <h1>Article Detail {articleId}</h1> </div> ); } const App = () => { return ( <Router> <Route path="/articles/:id" component={ArticleDetail} /> </Router> ); } export default App
用戶訪問 /articles/123
時,articleId
為“123”。
嵌套路由
復(fù)雜應(yīng)用有嵌套路由情況,如電商產(chǎn)品詳情頁有評論區(qū)。
import React from 'react'; import { Route, BrowserRouter as Router, Switch } from 'react-router-dom'; import ProductDetail from './ProductDetail'; import ProductReviews from './ProductReviews'; const App = () => { return ( <Router> <Switch> <Route path="/products/:id" component={ProductDetail}> <Route path="/products/:id/reviews" component={ProductReviews} /> </Route> </Switch> </Router> ); } export default App
訪問“/products/123/reviews”時,先渲染 ProductDetail
組件,再在其內(nèi)部合適位置渲染 ProductReviews
組件。
嵌套路由層級加深及應(yīng)用場景拓展
以企業(yè)級應(yīng)用為例,展示部門詳情頁、員工列表頁、員工個人詳情頁和員工績效頁等多層嵌套路由場景,通過合理配置實現(xiàn)頁面有序切換。
import React from 'react'; import { Route, BrowserRouter as Router, Switch } from 'react-router-dom'; const DepartmentDetail = props => { return ( <div> <h1>Department Detail</h1> {/* 展示部門相關(guān)信息 */} <Route path={`${props.match.path}/employees`} component={EmployeeList} /> </div> ); } const EmployeeList = props => { return ( <div> <h2>Employee List</h </div> {/* 展示員工列表 */} <Route path={`${props.match.path}/:employeeId`} component={EmployeeDetail} /> <Route path={`${props.match.path}/:employeeId/performance`} component={EmployeePerformance} /> </div> ); } const EmployeeDetail = props => { const { employeeId } = props.match.params; return ( <div> <h3>Employee Detail - ID: {employeeId}</h3> {/* 展示員工個人詳細(xì)信息 */} </div> ); } const EmployeePerformance = props => { const { employeeId } = props.match.params; return ( <div> <h3>Employee Performance - ID: {employeeId}</h3> {/* 展示員工績效相關(guān)信息 */} </div> ); } const App = () => { return ( <Router> <Switch> <Route path="/departments/:departmentId" component={DepartmentDetail} /> </Switch> </Router> ); } export default App
通過這樣的復(fù)雜示例,可以更好理解嵌套路由在構(gòu)建大型、功能豐富的應(yīng)用中是如何發(fā)揮作用的,以及如何根據(jù)實際業(yè)務(wù)需求去設(shè)計和配置多層嵌套的路由結(jié)構(gòu),更好地應(yīng)對復(fù)雜的頁面關(guān)系和功能模塊劃分
六、編程式導(dǎo)航
除 Link
組件,React-Router 支持編程式導(dǎo)航,通過 history
對象實現(xiàn),可在組件中用 props.history
獲?。ńM件需通過 Route
組件渲染)。
import React from 'react'; import { Route, BrowserRouter as Router, useNavigate } from 'react-router-dom'; const MyComponent = props => { const Navigate = useNavigate(); const handleClick = () => { Navigate('/about'); } return ( <div> <button onClick={handleClick}>Go to About</button> </div> ); } const App = () => { return ( <Router> <Route path="/" component={MyComponent} /> </Router> ); } export default App
點擊按鈕,調(diào)用 handleClick
函數(shù),導(dǎo)航到“/about”路徑,適用于表單提交成功等內(nèi)部邏輯導(dǎo)航。
七、路由權(quán)限
路由表
import { lazy } from 'react'; import Auth from './AuthRoute'; const Home = lazy(() => import('@/pages/Home')); const About = lazy(() => import('@/pages/About')); const List = lazy(() => import('@/pages/List')); const User = lazy(() => import('@/pages/User')); const NotFound = lazy(() => import('@/pages/NotFound')); const Router = [ { path: '/', element: <Home /> }, { path: '/about', element: <About /> }, { path: '/app/', element: ( // 自定義權(quán)限組件 <Auth> <BasicLayout /> </Auth> ), errorElement: <NotFound></NotFound>, children: [ { path: 'list', element: <List /> }, { path: 'list/user', element: <User /> } ] }, // 設(shè)置404頁面 { path: '*', element: <NotFound /> } ]; export default Router
權(quán)限組件
import { useEffect, useRef } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import { message } from 'antd'; import useUpdateEffect from '@/components/useUpdateEffect'; export default function Auth({ children }: any) { const location = useLocation().pathname; const didMountRef = useRef(false); const Navigate = useNavigate(); const token = localStorage.getItem('token'); useEffect(() => { if (didMountRef.current) { if (!token) { message.error('您未登錄,將跳轉(zhuǎn)'); setTimeout(() => { Navigate('/login'); }, 1000); } } else { didMountRef.current = true; } }, [token]); return children; }
404 頁面
import React from 'react'; const CommonLine = props => ( // 根據(jù)個人需求改動 <div>未找到該頁面</div> ); export default CommonLine
到此這篇關(guān)于React Router 一站式攻略:從入門到精通,掌握路由搭建與權(quán)限管控的文章就介紹到這了,更多相關(guān)React Router 路由搭建與權(quán)限管控內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React Native中ScrollView組件輪播圖與ListView渲染列表組件用法實例分析
這篇文章主要介紹了React Native中ScrollView組件輪播圖與ListView渲染列表組件用法,結(jié)合實例形式詳細(xì)分析了ScrollView組件輪播圖與ListView渲染列表組件具體功能、使用方法與操作注意事項,需要的朋友可以參考下2020-01-01React Native中WebView與html雙向通信遇到的坑
這篇文章主要介紹了React Native中WebView與html雙向通信的一些問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-01-01React利用scheduler思想實現(xiàn)任務(wù)的打斷與恢復(fù)
這篇文章主要為大家詳細(xì)介紹了React如何利用scheduler思想實現(xiàn)任務(wù)的打斷與恢復(fù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2024-03-03詳解create-react-app 自定義 eslint 配置
這篇文章主要介紹了詳解create-react-app 自定義 eslint 配置,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06React性能優(yōu)化系列之減少props改變的實現(xiàn)方法
這篇文章主要介紹了React性能優(yōu)化系列之減少props改變的實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01