什么是路由
路由是根据不同的 url 地址展示不同的内容或页面。
一个针对React而设计的路由解决方案、可以友好的帮你解决React components 到URl之间的同步映射关系
路由安装
https://reacttraining.com/react-router/web/guides/quick-start
npm install react-router-dom@5
路由使用
路由方法导入
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
定义路由以及重定向
<HashRouter>
<Switch>
<Route path="/films" component={Films}/>
<Route path="/cinemas" component={Cinemas}/>
<Route path="/center" component={Center}/>
<Redirect from="/" to="/films" />
{/* <Redirect from="/" to="/films" exact/>
<Route path="*" component={NotFound}/> */}
</Switch>
</HashRouter>
注意:
- exact 精确匹配 (Redirect 即使使用了exact, 外面还要嵌套Switch 来用)
- Warning: Hash history cannot PUSH the same path; a new entry will not be added to the history
stack,这个警告只有在hash 模式会出现。
嵌套路由
<Switch>
<Route path="/films/nowplaying" component={Nowplaying}/>
<Route path="/films/comingsoon" component={Comingsoon}/>
<Redirect from="/films" to="/films/nowplaying"/>
</Switch>
路由跳转方式
声明式导航
<NavLink to="/films" activeClassName="active">films</NavLink>
<NavLink to="/cinemas" activeClassName="active">cinemas</NavLink>
<NavLink to="/center" activeClassName="active">center</NavLink>
编程式导航
this.props.history.push(`/center`)
路由传参
this.props.history.push({pathname:'/user', query:{day:'Friday'}})
this.props.location.query.day
this.props.histrory.push({pathname:'/user', state: {day:'Friday'}})
this.props.location.state.day
路由拦截
<Route path="/center" render={()=>isAuth()?<Center/>:<Login/>}/>
withRouter的应用与原理
import { withRouter } from "react-router";
withRouter(MyComponent);
withRouter(connect(...)(MyComponent))
React Router(V6)
简介
- react-router :核心模块,包含 React 路由大部分的核心功能,包括路由匹配算法和大部分核心组件和钩子
- react-router-dom:React应用中用于路由的软件包,包括react-router的所有内容,并添加了一些特定于 DOM 的 API,包括但不限于BrowserRouter、HashRouter和Link
- react-router-native: 用于开发React Native应用,包括react-router的所有内容,并添加了一些特定于 React Native 的 API,包括但不限于NativeRouter和Link。
对比V5
- 包大小对比
- 特性变更
path:与当前页面对应的URL匹配。
element:新增,用于决定路由匹配时,渲染哪个组件。代替,v5的component和render。 - 让嵌套路由更简单
- useNavigate代替useHistory
- 移除了的activeClassName 和 activeStyle
- 钩子useRoutes代替react-router-config
- https://reactrouter.com/docs/en/v6/upgrading/v5
用法详解
- 一级路由与多级路由
<Routes>
{/*<Route path="/" element={<Film/>}/>*/}
<Route index element={<Film/>}/>
<Route path="/film" element={<Film/>}/>
<Route path="/cinema" element={<Cinema/>}/>
<Route path="/center" element={<Center/>}/>
</Routes>
ndex用于嵌套路由,仅匹配父路径时,设置渲染的组件。
解决当嵌套路由有多个子路由但本身无法确认默认渲染哪个子路由的时候,可以增加index属性来指定默认路由。index路由和其他路由不同的地方是它没有path属性,他和父路由共享同一个路径。
- 路由重定向
(1) 官方推荐方案 1: 使用 Navigate 组件替代
<Routes>
{/* <Route index element={<Film/>}/> */}
<Route path="/film" element={<Film/>}/>
<Route path="/cinema" element={<Cinema/>}/>
<Route path="/center" element={<Center/>}/>
<Route path="*" element={<Navigate to="/film"/>}/>
</Routes>
(2) 官方推荐方案 2: 自定义 Redirect 组件
<Route path="*" element={<Redirect to="/film"/>}/>
function Redirect({to}){
const navigate =useNavigate()
useEffect(() => {
navigate(to,{replace:true})
})
return null
}
(3) 404如何实现?
<Route path="/" element={<Redirect to="/film"/>}/>
<Route path="*" element={<NotFound/>}/>
- 嵌套路由
<Route path="/film" element={<Film/>}>
{/* <Route index element={<Nowplaying/>}/> */}
<Route path="" element={<Redirect to="/film/nowplaying"/>}/>
<Route path="nowplaying" element={<Nowplaying/>}/>
<Route path="comingsoon" element={<Comingsoon/>}/>
</Route>
Film组件 <Outlet></Outlet>
- 声明式导航与编程式导航
<ul>
<li><NavLink to="nowplaying" className={({ isActive }) => isActive ?
"kerwinactive" : ""} >正在热映</NavLink></li>
<li><NavLink to="comingsoon" className={({ isActive }) => isActive ?
"kerwinactive" : ""}>即将上映</NavLink></li>
</ul>
//url传参
const navigate = useNavigate()
navigate(`/detail?id=${id}`)
//获取url参数
import { useSearchParams } from 'react-router-dom'
const [searchParams, setSearchParams] = useSearchParams()
// 获取参数
searchParams.get('id')
// 判断参数是否存在
searchParams.has('id')
// 同时页面内也可以用set方法来改变路由
setSearchParams({"id":2})
5.动态路由
//跳转页面,路由传参
navigate(`/detail/${id}`)
//配置动态路由
<Route path="/detail/:id" element={<Detail/>}/>
//获取动态路由参数
const {id} = useParams()
6.路由拦截
<Route path="/center" element={
<AuthComponent>
<Center></Center>
</AuthComponent>
}/>
function AuthComponent({children}){
return localStorage.getItem("token")?
children:<Redirect to="/login"/>
}
7.路由模式
import {HashRouter} from 'react-router-dom'
import {BrowserRouter} from 'react-router-dom'
8.withRouter / 类组件跳转方法
import {
useLocation,
useNavigate,
useParams
} from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let push = useNavigate();
let params = useParams();
return (
<Component
{...props}
history={{ location, push, params }}
/>
)
}
return ComponentWithRouterProp;
}
export default withRouter
- 路由懒加载
const LazyLoad = (path) => {
const Comp = React.lazy(() => import(`../views/${path}`))
return (
<React.Suspense fallback={<>加载中...</>}>
<Comp />
</React.Suspense>
)
}
export default function MRouter() {
return (
<Routes>
{/* <Route index element={<Film/>}/> */}
<Route path="/film" element={LazyLoad("Film")}>
{/* <Route index element={<Nowplaying/>}/> */}
<Route path="" element={<Redirect to="/film/nowplaying"/>}/>
<Route path="nowplaying" element={LazyLoad("film/Nowplaying")}/>
<Route path="comingsoon" element={LazyLoad("film/Comingsoon")}/>
</Route>
<Route path="/cinema" element={LazyLoad("Cinema")}/>
<Route path="/login" element={LazyLoad("Login")}/>
<Route path="/center" element={<AuthComponent>
{LazyLoad("Center")}
</AuthComponent>}/>
<Route path="/detail/:id" element={LazyLoad("Detail")}/>
<Route path="/" element={<Redirect to="/film"/>}/>
<Route path="*" element={LazyLoad("NotFound")}/>
</Routes>
)
}
- useRoutes钩子配置路由
export default function MRouter() {
const element = useRoutes([
{
path:"/film",
element:LazyLoad("Film"),children:[
{
path:"",
element:<Redirect to="/film/nowplaying"/>
},
{
path:"nowplaying",
element:LazyLoad("film/Nowplaying")
},
{
path:"comingsoon",
element:LazyLoad("film/Comingsoon")
}
]},
{
path:"/cinema",
element:LazyLoad("Cinema")
},
{
path:"/login",
element:LazyLoad("Login")
},
{
path:"/center",
element: <AuthComponent>
{LazyLoad("Center")}
</AuthComponent>
},
{
path:"/detail/:id",
element:LazyLoad("Detail")
},
{
path:"/",
element:<Redirect to="/film"/>
},
{
path:"*",
element:LazyLoad("NotFound")
},
])
return element
}