目录
一、react-router
和vue一样,react应用也是单页面应用(spa),所以也需要引入路由来控制不同组件的展示和隐藏来实现不同页面的效果,保持 UI 与 URL 的同步。
安装:
npm i react-router-dom // 不指定版本号就是最新版本
可以看到,最新的版本是6.3.0,也就是react-router v6。
二、路由模式
2.1 history模式
history 模式,引入对应的组件是 BrowserRouter 组件。
import React from "react"
import ReactDOM from "react-dom/client"
// 引入路由组件 使用 as 创建一个别名
// 使用别名 以后可以在这改,就可以轻松实现路由模式的切换
import {BrowserRouter as RouterSelf} from "react-router-dom"
import App from "./App"
const container =document.getElementById("root")
const root =ReactDom.createRoot(container)
// 用来包裹 App 这个组件即可
root.render(
<RouterSelf>
<App/>
</RouterSelf>
)
2.2 hash模式
hash 模式的路由,对应引入的是 HashRouter 组件。
import React from "react"
import ReactDOM from "react-dom/client"
// 引入路由组件 使用 as 创建一个别名
// 使用别名 以后可以在这改,就可以轻松实现路由模式的切换
import {HashRouter as RouterSelf} from "react-router-dom"
import App from "./App"
const container =document.getElementById("root")
const root =ReactDom.createRoot(container)
// 用来包裹 App 这个组件即可
root.render(
<RouterSelf>
<App/>
</RouterSelf>
)
至于hsitory和hash模式的区别,我在vue路由中写过一篇区分二者的博客:VueRouter — vue路由hash模式和history模式
三、路由配置
3.1 配置
我们使用路由组件包含了App组件,所以应该在App组件中配置路由。
App.jsx
import {Routes, Route,Navigate} from "react-router-dom"
import HomePage from "./pages/HomePage";
import LoginPage from "./pages/LoginPage";
import HelpPage from "./pages/HelpPage";
import AboutPage from "./pages/AboutPage";
function App(){
return(
<Routes>
{/*
path 后面书写的是路径
element 后面书写的是对应的组件
*/}
<Route path="/login" element={<LoginPage />}></Route>
{/*
嵌套路由:
v6 版本的子路由直接被父路由包裹
*/}
<Route path="/home" element={<HomePage />}>
{/* 这里书写的就是嵌套的路由*/}
<Route path="about" element={<AboutPage />}></Route>
<Route path="help" element={<HelpPage />}></Route>
</Route>
{/*
路由的重定向
这里使用的是 Navigate 组件
因为路由表的匹配是从上往下匹配的,所以重定向的路由写在最下面
*/}
<Route path="*" element={<Navigate to="/login" />} ></Route>
</Routes>
)
}
export default App;
HomePage.jsx:
Link 和 NavLink 都可以实现路由跳转,但是 NavLink 自身存在一个 active的类名,可以在里面设置激活之后的样式。
例如这里,我设置.active类的样式。
3.2 编程式导航
useNavigate()
函数会返回一个函数,这个函数暂且叫做navigate,名字随意取,navigate用来实现编程导航的跳转。参考vue中的router.push等方法。
const navigate=useNavigate()
navigate("/login") // 这种是push的方式
navigate("/login",{replace:true}) // 第二个参数表示路由跳转之后是push进去,还是直接替换之前的组件,replace:true 那么就是替换之前的组件,不会有历史,不能退回到前一步
// 后退一下 下面这个函数的功能就和 History 里面的 go() 函数用法类似
navigate(-1)
3.2 默认子路由
给子route组件设置index属性,那么改路径下就会默认显示该router的element所对应的组件。
此时/home的Outlet默认会显示AboutPage组件,但是不能设置path属性。
四、路由传参
4.1 params传参
需要在定义路由时声明参数名称:
<Route path="single-blog/:id" element={<SingleBlog/>}></Route>
多个参数在后面递加/:paramsName即可。
跳转时携带参数:
<NavLink to="/single-blog/123" >博客详情</NavLink>
编程式:
const navigate = useNavigate();
navigate.push('/single-blog/123')
组件中获取:
const parmas = useParams();
console.log(parmas);//{id: 123}
页面刷新,参数不会失效。
4.2 search传参
不需要在定义路由时声明参数名称,和超链接请求跳转非常相似,使用?和&拼接参数。
<NavLink to="/single-blog?id=123&&mode='light'" >博客详情</NavLink>
编程式:
const navigate = useNavigate();
navigate.push("/single-blog?id=123&&mode='light'");
组件中获取,需要使用useSearchParams:
const [search]=useSearchParams()
console.log(search.get('id'));//123
console.log(search.get('mode'));//light
属性页面,参数不会失效。
4.3 state传参
不需要在定义路由时声明参数名称,只需在Link或者NavLink上声明state属性并赋值即可。
<NavLink to={'/single-blog'} state={{id:123,mode:'light'}}>博客详情</NavLink>
编程式:
const navigate = useNavgate();
navigate('/single-blog',{
replace:false,
state:{
id: 123,
mode: 'light'
}
})
组件中获取,需要使用useLocation:
const {state: {id,mode} } = useLocation();
console.log(id,mode);//123,light
五、路由守卫(拦截)
创建一个路由鉴权组件:
AuthRoute.jsx
import { Navigate , useLocation } from "react-router"
export default function AuthRoute({children}) {
//获取到locationStorage中的token
const token = localStorage.getItem('token')
//获取location
const { pathname} = useLocation()
if(!token){
return <Navigate to="/login" state={{returnURL:pathname}}></Navigate>
}
//如果存在 则渲染标签中的内容
return children;
}
需要鉴权的组件放在AuthRoute标签中:
<Route path="/profile" element={
<AuthRoute>
<Profile></Profile>
</AuthRoute>
}></Route>