react 路由 react-router-dom

补充一个:类组件,无法使用 useNavigate 这个hook函数,所以,编写一个高阶组件

javascript 复制代码
import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom'

// 类组件,无法使用 useNavigate 这个hook函数,
// 所以,编写一个高阶组件,
function withRouter(WrapperComponent) {
	// 返回一个函数式组件
	return function (props) {
		// 1、导航的跳转
		const navigate = useNavigate()
		
		// 2、动态路由的参数,如:/detail/:id
		const params = useParams()
		
		// 3、查询字符串参数,如:/user?name=why&age=18
		// location、query 是两种方式
		const location = useLocation()
		console.log('location=', location)
		const [searchParams, setSearchParams] = useSearchParams()
		const query = Object.fromEntries(searchParams)
		console.log('query=', query)
		
		const router = { navigate, params, query }
		
		// props原样传回去
		return <WrapperComponent {...props} router={router}></WrapperComponent>
	}
}

export default withRouter

使用这个 withRouter

javascript 复制代码
import React, { PureComponent } from 'react'

// Link:用于声明式导航(类似 <a> 标签,但不会触发页面刷新)
// OutLet:子路由的占位符,<Outlet /> 是子路由组件的渲染位置,根据当前 URL 路径,自动匹配对应的子路由组件并渲染到此处。
// useNavigate:Hook,用于编程式导航(只能在函数组件中使用)
import { Link, Outlet, useNavigate } from 'react-router-dom'

import { withRouter } from '../hoc'

export class Home extends PureComponent {
	navigateTo(path) {
		const { navigate } = this.props.router
		navigate(path)
	}

	render() {
		return (
			<div>
				<h1>HomePage</h1>
				
				<div className="home-nav">
					<Link to="/home/recommend">推荐</Link>
					<Link to="/home/ranking">排名</Link>
					
					<button onClick={e => this.navigateTo('/home/songmenu')}>歌单</button>
				</div>
				
				` 有了占位符,才能显示子路由在哪个位置渲染,
				  没有占位符,子路由根本就不会渲染到页面上。`
				<Outlet />
			</div>
		)
	}
}

// export default Home
export default withRouter(Home)



补充一个

  • 动态路由参数
javascript 复制代码
定义:
	{ path: '/detail/:id', element: <Detail /> }

使用:
	在 Detail 组件中通过 useParams() 获取参数:
	import { useParams } from 'react-router-dom'
	
	function Detail() {
	  const { id } = useParams() // id = 路径中的动态值(如 "123")
	  return <div>Detail ID: {id}</div>
	}
  • 查询参数
javascript 复制代码
定义:
	<Link to="/user?name=why&age=18">用户</Link>

使用:
	在 User 组件中通过 useSearchParams() 获取:
	import { useSearchParams } from 'react-router-dom'
	
	function User() {
	  const [searchParams] = useSearchParams()
	  const name = searchParams.get('name') // "why"
	  const age = searchParams.get('age')   // "18"
	  return <div>User: {name}, Age: {age}</div>
	}



安装及引入配置:npm i react-router-dom

src/index.js

javascript 复制代码
// 导入 React 核心库和 Suspense 组件(用于代码分割和懒加载)
import React, { Suspense } from 'react'
// 导入 ReactDOM 的客户端渲染方法(React 18+ 新 API)
import ReactDOM from 'react-dom/client'
// 导入根组件 App
import App from './App'

`1、安装路由:npm i react-router-dom`
`2、使用 HashRouter 的路由模式`
import { HashRouter } from 'react-router-dom'

// 创建根渲染节点,绑定到 HTML 中 id="root" 的 DOM 元素
const root = ReactDOM.createRoot(document.getElementById('root'))

root.render(
  // <React.StrictMode>
  //   {/*
  //     3、HashRouter 包裹 <App />
  //     4、配置 Routes,就是映射关系:path -> component
  //   */}
  //   <HashRouter>
  //     <App />
  //   </HashRouter>
  // </React.StrictMode>

  // <HashRouter>
  //   <App />
  // </HashRouter>

   ` 打包的时候,如果要对 About、Login 分别单独打包处理
   * Suspense 的作用;
   * 配合 React.lazy 实现组件懒加载,如:const About = React.lazy(() => import('../pages/About'))
   * 当子组件尚未加载完成时,显示 fallback 的加载状态(此处是 <h3>Loading...</h3>)
   * 打包工具(如:Webpack)会为动态导入的组件生成单独 chunk。`
	<HashRouter>
		<Suspense fallback={<h3>Loading...</h3>}>
			<App />
		</Suspense>
	</HashRouter>
)

如果是类组件

App.jsx

javascript 复制代码
import React, { PureComponent } from 'react'

// 配置映射关系
import { Routes, Route, Link, NavLink, Navigate } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Login from './pages/Login'
import NotFound from './pages/NotFound'
import Category from './pages/Category'
import Order from './pages/Order'

import HomeRecommend from './pages/HomeRecommend'
import HomeRanking from './pages/HomeRanking'

export class App extends PureComponent {
	render() {
		return (
			<div className="app">
				<div className="header">
					<span>header</span>
					<div className="nav">
						`NavLink标签,会带一个"active"的class,可以通过这个class编写样式`
						<NavLink to="/home">首页</NavLink>
						<NavLink to="/about">关于</NavLink>
						
						`也可以这样`
						<NavLink to="/home" style={({isActive}) => ({color: isActive ? 'red' : ''})}>首页</NavLink>
						<NavLink to="/about" className={({isActive}) => (isActive ? 'link-active' : '')}>关于</NavLink> 
						
						<Link to="/home">首页</Link>
						<Link to="/about">关于</Link>
					</div>
				</div>
			  
				<hr />
			
				<div className="content">
					`配置映射关系`
					<Routes>
						<Route path="/" element={<Navigate to="/home" />}></Route>
						
						<Route path="/home" element={<Home />}>
						<Route path="/home" element={<Navigate to="/home/recommend" />}></Route>
						<Route path="/home/recommend" element={<HomeRecommend />}></Route>
						<Route path="/home/ranking" element={<HomeRanking />}></Route>
						</Route>
						
						<Route path="/about" element={<About />}></Route>
						
						<Route path="/order" element={<Order />}></Route>
						
						<Route path="/category" element={<Category />}></Route>
						
						<Route path="/login" element={<Login />}></Route>
						
						`【* :代表通配符,当以上所有路径都没有匹配的时候,就会匹配到这个 * 】`
						<Route path="*" element={<NotFound />}></Route>
					</Routes>
				</div>
			
				<hr />
				<div className="footer">footer</div>
			</div>
		)
	}
}

export default App

如果是函数式组件(不使用路由配置)

  • Routes 包裹所有 Route 的容器,负责路由匹配
  • Route 定义,路径与组件的映射关系
  • Link 声明式导航组件(类似 标签,无刷新跳转)
  • NavLink 增强版 Link,可添加激活状态的样式
  • Navigate 用于重定向(如:默认跳转)
  • useNavigate Hook 用于编程式导航(如:按钮点击跳转)

App.jsx

javascript 复制代码
import React from 'react'

// 配置映射关系
import { Routes, Route, Link, NavLink, Navigate, useNavigate } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Login from './pages/Login'
import NotFound from './pages/NotFound'
import Category from './pages/Category'
import Order from './pages/Order'
import User from './pages/User'

import HomeRecommend from './pages/HomeRecommend'
import HomeRanking from './pages/HomeRanking'
import HomeSongMenu from './pages/HomeSongMenu'
import Detail from './pages/Detail'

export function App(props) {
	const navigate = useNavigate()
	
	function navigateTo(path) {
		navigate(path)
	}

	return (
		<div className="app">
			<div className="header">
				<span>header</span>
				<div className="nav">
					`声明式导航`
					<Link to="/home">首页</Link>
					<Link to="/about">关于</Link>
					<Link to="/login">登录</Link>
					
					`编程式导航`
					<button onClick={e => navigateTo('/category')}>分类</button>
					<span onClick={e => navigateTo('order')}>订单</span>
					
					` 带查询参数的导航
		              在 User 组件中通过 useSearchParams() 获取:
			              const [searchParams] = useSearchParams()
			              const name = searchParams.get('name') // "why"
			              const age = searchParams.get('age')   // "18" `
					<Link to="/user?name=why&age=18">用户</Link>
				</div>
			</div>
		  
			<hr />
		
			<div className="content">
				`配置映射关系`
				<Routes>
					<Route path="/" element={<Navigate to="/login" />}></Route>
					
					<Route path="/login" element={<Login />}></Route>
					
					<Route path="/home" element={<Home />}>
						`默认子路由重定向`
						<Route path="/home" element={<Navigate to="/home/recommend" />}></Route>
						<Route path="/home/recommend" element={<HomeRecommend />}></Route>
						<Route path="/home/ranking" element={<HomeRanking />}></Route>
						<Route path="/home/songmenu" element={<HomeSongMenu />}></Route>
					</Route>
					
					<Route path="/about" element={<About />}></Route>
					
					<Route path="/order" element={<Order />}></Route>
					
					<Route path="/category" element={<Category />}></Route>
					
					`路由传参 - 方式1 - 动态路由参数
			         如:
			            访问 /detail/123 时,Detail 组件可通过 useParams() 获取 id 参数:
			            const { id } = useParams() // id = "123" 。`
					<Route path="/detail/:id" element={<Detail />}></Route>
					
					`查询参数接收页`	
					<Route path="/user" element={<User />}></Route>
					
					`【* :代表通配符,当以上所有路径都没有匹配的时候,就会匹配到这个 * 】`
					<Route path="*" element={<NotFound />}></Route>
				</Routes>
			</div>
		
			<hr />
			
			<div className="footer">footer</div>
		</div>
	)
}

export default App

函数式组件(使用路由配置)

App.jsx
javascript 复制代码
import React from 'react'

// 配置映射关系
import { Routes, Route, Link, NavLink, Navigate, useNavigate, useRoutes } from 'react-router-dom'

import routes from './router'

export function App(props) {
	const navigate = useNavigate()
	
	function navigateTo(path) {
		navigate(path)
	}

	return (
		<div className="app">
			<div className="header">
				<span>header</span>
				<div className="nav">
					<Link to="/home">首页</Link>
					<Link to="/about">关于</Link>
					<Link to="/login">登录</Link>
					
					<button onClick={e => navigateTo('/category')}>分类</button>
					<span onClick={e => navigateTo('order')}>订单</span>
					
					<Link to="/user?name=why&age=18">用户</Link>
				</div>
			</div>

			<hr />
		
			<div className="content">
				{/* 配置映射关系 */}
				{/* 使用路由配置 */}
				{useRoutes(routes)}
			</div>
		
			<hr />
			
			<div className="footer">footer</div>
		</div>
	)
}

export default App
router/index.js 路由配置文件
javascript 复制代码
import { Navigate } from 'react-router-dom'
import React from 'react'

import Home from '../pages/Home'

`打包的时候,如果要对 About、Login 分别单独打包处理,就可以使用懒加载。`
// import About from '../pages/About'
// import Login from '../pages/Login'

import NotFound from '../pages/NotFound'
import Category from '../pages/Category'
import Order from '../pages/Order'
import User from '../pages/User'

import HomeRecommend from '../pages/HomeRecommend'
import HomeRanking from '../pages/HomeRanking'
import HomeSongMenu from '../pages/HomeSongMenu'
import Detail from '../pages/Detail'

	`
	打包的时候,如果要对 About、Login 分别单独打包处理,就可以使用懒加载
	为什么使用这种形式能够单独打包呢?
	因为,这是,webpack的特性。`
/*
  还需要这样处理一下!!!
  // 打包的时候,如果要对 About、Login 分别单独打包处理
  <HashRouter>
    <Suspense fallback={<h3>Loading...</h3>}>
      <App />
    </Suspense>
  </HashRouter>
*/
const About = React.lazy(() => import('../pages/About'))
const Login = React.lazy(() => import('../pages/Login'))

const routes = [
  {
    path: '/',
    element: <Navigate to="/home" />
  },
  {
    path: '/home',
    element: <Home />,
    children: [
      {
        path: '/home',
        element: <Navigate to="/home/recommend" />
      },
      {
        path: '/home/recommend',
        element: <HomeRecommend />
      },
      {
        path: '/home/ranking',
        element: <HomeRanking />
      },
      {
        path: '/home/songmenu',
        element: <HomeSongMenu />
      }
    ]
  },
  {
    path: '/about',
    element: <About />
  },
  {
    path: '/login',
    element: <Login />
  },
  {
    path: '/category',
    element: <Category />
  },
  {
    path: '/order',
    element: <Order />
  },
  {
    path: '/detail/:id',
    element: <Detail />
  },
  {
    path: '/user',
    element: <User />
  },
  {
    path: '*',
    element: <NotFound />
  }
]

export default routes
相关推荐
萌萌哒草头将军2 小时前
🚀🚀🚀React Router 现在支持 SRC 了!!!
javascript·react.js·preact
薛定谔的算法3 小时前
# 从0到1构建React项目:一个仓库展示应用的架构实践
前端·react.js
薛定谔的算法6 小时前
# 前端路由进化史:从白屏到丝滑体验的技术突围
前端·react.js·前端框架
Adolf_19937 小时前
React 中 props 的最常用用法精选+useContext
前端·javascript·react.js
前端小趴菜057 小时前
react - 根据路由生成菜单
前端·javascript·react.js
極光未晚7 小时前
React Hooks 中的时空穿梭:模拟 ComponentDidMount 的奇妙冒险
前端·react.js·源码
孟陬10 小时前
写一个根据屏幕尺寸动态隐藏元素的插件 🧩 - tailwindcss 系列
react.js
啃火龙果的兔子10 小时前
nextjs+react项目如何代理本地请求解决跨域
前端·react.js·前端框架
WildBlue10 小时前
🚀 React Fragment:让代码呼吸的新鲜空气
前端·react.js