# React Router(V6)
[Tutorial v6.8.1 | React Router](https://reactrouter.com/en/main/start/tutorial)
> v6不兼容 v5, 变化较大
```sh
# 安装最新版v6
pnpm add react-router-dom
```
## helloRouter
```jsx
/**
* react router 使用步骤
* 1. 安装react-router-dom包
* 2. 在main.jsx 中引入BrowserRouter组件
* 3. 将BrowserRouter设置为根组件
* 4. 在App.jsx 中引入 Routes, Route 组件
* 5. 用 Routes组件包裹Route组件
*/
```
```jsx
/**
* Routes v6新增的组件
* 类似v5的Switch, 都是用于Route的容器
* Routes中的Route只有一个会被匹配 不用加exact了
* v6中 component render children 都不能用了
* 改为element指定要挂载的组件
*/
```
```jsx
// @/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import {BrowserRouter as Router} from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')).render(
)
```
```jsx
// @/App.jsx
import { Routes, Route } from 'react-router-dom'
import Menu from './components/Menu'
import Home from './components/Home'
import About from './components/About'
function App() {
return (
} />
} />
)
}
export default App
```
```jsx
// @/components/Home.jsx
const Home = ()=>{
return (
主页
)
}
export default Home
```
```jsx
// @/components/About.jsx
const About = ()=>{
return (
关于我们
)
}
export default About
```
```jsx
// @/components/Menu.jsx
import { Link } from 'react-router-dom'
const Menu = () => {
return (
)
}
export default Menu
```
## 钩子
```jsx
// useParams() 不变
// useLocation() 不变
// [x] useRouteMatch() 没有了
// useMatch(path) 检查当前url是否匹配某个路由,需要传参, 例如 useMatch('/about'),不匹配返回null, 匹配返回对象
// [x] useHistory() 没有了
// useNavigage() 获取一个用来跳转的函数
// ...
import {useNavigate} from 'react-router-dom'
// ...
const nav = useNavigate()
const clickHandler = ()=>{
nav('/about') // 默认使用push跳转,有历史记录
nav('/about',{replace:true}) // 使用replace跳转
}
```
## 嵌套路由+ Outlet
```jsx
/**
* V6默认严格匹配,想取消,可以 path='/about/*'
* Outlet 用来表示嵌套路由中的组件
* 当路径匹配成功, Outlet表示嵌套路由中的组件
* 当匹配失败, Outlet相当于不存在
* 有点像vue的插槽
*/
```
```jsx
// @/App.jsx
// Route嵌套Route
// '/about'可以省略成'about', '/about/hello'省略成'hello'
import { Routes, Route } from 'react-router-dom'
import Menu from './components/Menu'
import Home from './components/Home'
import About from './components/About'
import Hello from './components/Hello'
import Word from './components/Word'
function App() {
return (
} />
} >
} />
} />
)
}
export default App
```
```jsx
// @/components/About
// 添加Outlet组件
// 会智能匹配 hello组件或者word组件
import { Outlet } from 'react-router-dom'
const About = ()=>{
return (
关于我们
)
}
export default About
```
## Navigate组件
> V5使用 Redirect 重定向, V6使用 Navigate 组件
```jsx
// 默认使用push跳转
{!isLogin && }
// 添加replace使用replace跳转
{!isLogin && }
// 传递参数
{!isLogin && } // 在跳转后的页面用useLocation()可以拿到
```
## NavLink组件
> V5的 activeStyle activeClassName 取消了
> V6 改成style={()=>{}}
1. 使用style
```jsx
{
return isActive ? { backgroundColor: 'yellow' } : null
}}>
about/word
```
2. 使用className
```jsx
import classes from './Menu.module.css'
// ...
{
return isActive ? classes.active : ''
}}>
about/hello
```
```css
/* Menu.module.css */
a.active {
background-color: green;
}
```
## 高阶组件实现路由守卫
```jsx
// 没有登录访问权限页面,跳转登录页面
: }
/>
```
提取成组件
```jsx
import { useSelector } from 'react-redux'
import { Navigate } from 'react-router-dom'
const NeedAuth = props => {
const { isLogin } = useSelector(state => state.auth)
return isLogin ? props.children :
}
export default NeedAuth
```
```jsx
}
/>
```
想登录成功后返回原来的页面, 使用 useLocation 和 Navigate state 来传递和获取 path
```jsx
import { useSelector } from 'react-redux'
import { Navigate,useLocation } from 'react-router-dom'
const NeedAuth = props => {
const location = useLocation()
const { isLogin } = useSelector(state => state.auth)
return isLogin ? props.children :
}
export default NeedAuth
```