问题导向
react生命周期何时调用?以及应用场景?
如果你都有了答案,可以忽略本文章,或去react学习地图寻找更多答案
简单使用
第一步:安装react-router-dom
yarn add react-router-dom
第二步:从react-router-dom引出路由组件
import {
BrowserRouter, Switch, Route } from 'react-router-dom'
第三步:在App页面使用
import React from 'react'
import {
BrowserRouter, Switch, Route } from 'react-router-dom'
import Home from './pages/home'
import Order from './pages/order'
import NotFount from './pages/notFount'
const App = () => {
return (
<>
<BrowserRouter>
<Switch>
<Redirect exact from='/' to='/home' />
<Route path="/home" component={
Home} />
<Route path="/order" component={
Order} />
<Route component={
NotFount} />
</Switch>
</BrowserRouter>
</>
)
}
export default App
react-router-dom导出的组件
HashRouter 和 BrowserRouter 根容器
Switch 精准匹配
Route 路由规则
Link 声明式跳转
NavLink 声明式跳转 + 样式
Redirect 重定向
withRouter 高阶组件,将组件变成路由组件
HashRouter 和 BrowserRouter
定义:路由的根容器,记录浏览记录,并传入各组件数成员,任何组件都可以使用历史对象
HashRouter生成的路由地址前面会加一个#号
属性:basename统一前缀
<BrowserRouter basename="/api">
</BrowserRouter>
Switch
会匹配第一条符合的子规则,解决模糊匹配,不再需要exact
需要注意排序,从最特别的到最一般的,一般与404页面配合使用
Route
定义:路由规则,注册/定义路由
path属性:告诉路由什么URL地址
component属性:告诉路由去哪个组件,并向组件传递了3个属性,组件可通过props获取
如果想让路由规则,进行精确匹配,可以为 Route,添加 exact 属性,表示启用精确匹配模式
从路由规则中,提取匹配到的参数,可以使用props来访问
Route对象的3个属性:
用法
第一种:
<Route exact path="/home" component={
Home} />
第二种:该方式获取不到路由对象
<Route path="/home" component={
() => <Home />} />
第三种:传递参数
<Route path="/home/:type/:id" component={
Home} />
第四种:可选参数:如果只写一个参数,year就获取不到
<Route path="/shop/rating/:year?/:mouth"component={
ShopRating} />
第五种:render写法:传递自定义属性,使用props接收
可以在浏览器的react路由中看到该参数,props是Route自带的3个参数
<Route path='/about' render={
(prosp) => <About user={
this.state.user}, {
...props}/>} />
第六种:不写path,404,没有匹配到的url地址,将会匹配该页面
<Route component={
NotFound}></Route>
Route渲染内容的三种方式:children,component,render
特点:互斥,三种只能使用其中一种
共性:都能获取props
区别:
- children不管路由是否匹配,都会渲染
- component路由匹配才会渲染,源码使用createElement,如果使用component={() => },会不匹配,造成先卸载再挂载,浪费性能,如果需要这种方式,可用render替代
- render路由匹配时才会渲染
<Route exact path='/' children={
fn} component={
HomePage} render={
fn}/>
Link
定义:路由的跳转链接,路由设置,单页应用的核心,默认Link = a标签
使用to替换a标签的href属性,页面没有跳转,因为Link内部的a标签有一个onclick的函数调用,阻止了页面跳转,只会更新URL,URL改变,route则会匹配到
用法
第一种:字符串用法
<Link to="/home">首页</Link>
第二种:动态传递参数
<Link to={
`/home/${
12345}`}>首页</Link>
第三种:传递查询字符串
<Link to={
`/shop/info?id=${
123}`}>shop</Link>
NavLink
定义:是Link的升级版,会在匹配上当前的url的时候给已经渲染的元素添加参数,组件的属性有:
activeClassName(string):设置选中样式,默认值为active
activeStyle(object):当元素被选中时,为此元素添加样式
exact(bool):为true时,只有当导致和完全匹配class和style才会应用
strict(bool):为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线
isActive(func):判断链接是否激活的额外逻辑的功能
用法
<NavLink
to="/home"
avtiveClssName="selected" //选中类名方式
activeStyle={
{
//选中对象方式
fontWeight: 'bold',
color: 'red'
}}
>home</NavLink>
Redirect重定向
定义:当url匹配时,重定向到to的页面,to 也可以是一个对象
用法
写法一:自动重定向
<Redirect to="/admin/home"/>
写法二:规则重定向,如果是/,重定向到/home
<Redirect from="/" to="/home" />
withRouter
定义:将非路由组件变成路由组件
非路由组件:获取不到history等路由对象,所以要转成路由对象
用法
const {
withRouter } from 'react-router-dom'
const App = () => {
}
export default withRouter(App) 变成路由组件
路由传参
默认情况下,路由中的规则,是模糊匹配的,如果路由可以部分匹配成功,就会展示这个路由对应的组件,如果要匹配参数,可以在 匹配规则中,使用 “:” 修饰符,表示这个位置匹配到的是参数
<Route exact path="/movie/:type/:id" component={
Movie}></Route>
1.动态路由参数
localhost:3000/detail/2
<Link to={
`/detail/'${
id}`}
<Route exact path='/detail:id' component={
Detail}>
查询参数可选: +?,正则表达式
localhost:3000/2020/
<Route exact path='/detail/:year?/:mouth' component={
Detail}>
2.路由查询字符串
localhost:3000/detail?id=2
<Link key={
index} to={
`/detail?id=${
id}`}
<Route exact path='/detail' render={
() => <div>detail</div>}>
获取路由参数
第一种方式:props
props.history
第二种方式:hook
import {
useParams, useRouteMatch, useLocation, useRouteMatch} from 'react-router-dom'
路由组件懒加载
配合Suspense和lazy使用
Suspense的fallback是未加载完成时显示的内容
import {
BrowserRouter,Route,Switch} from 'react-router-dom'
import React, {
Suspense,lazy} from 'react'
const Home = lazy(() => import('./home'))
const Order = lazy(() => import('./Order'))
const App = () => {
<BrowserRouter>
<Switch>
<Suspense fallback={
<div>loading...</div>}>
<Route path='/' component={
Home} />
<Route path='/order' component={
Order} />
</Suspense>
</Switch>
</BrowserRouter>
}
路由守卫(简单写法)
<Route path="/movies/:id"
路由条件渲染
render={
props => {
if(!user) return <Redirect to="/login" />
return <Movie {
...props} />
})}
/>
封装protectedRoute组件,跳转回未登陆前的页面
使用
<ProtectedRoute
path="/movies/:id"
component={
MovieForm}
/>
封装
import React from 'react'
import {
Route, Redirect } from 'react-router-dom'
import {
getUserInfoFormToken } from '../services/authServices'
属性由路由传递属性,component属性要大写,因为要返回一个组件
const ProtectedRoute = ({
component: Component, render, ...rest }) => {
return (
<Route
//path属性已经在rest里面了
{
...rest}
render={
(props) => {
//如果用户没有登录,就跳到login页
if (!getUserInfoFormToken()) {
return (
<Redirect
//to可以是字符串,也可以是对象
to={
{
pathname: '/login',
// 存下用户来之前的网站,在用户登录时判断state是否存在,是就去,否则去首页
state: {
from: props.location },
}}
/>
)
}
return Component ? <Component {
...props} /> : render(props)
}}
/>
)
}
export default ProtectedRoute
集成redux
import React from 'react'
import {
connect } from 'react-redux'
import {
Route, Redirect } from 'react-router-dom'
const ProtectedRoute = ({
menus,
component: Component,
render,
location,
...rest
}) => {
let path = location.pathname
if (path.indexOf('/product') === 0) {
path = '/product'
}
return (
<Route
{
...rest}
render={
(props) => {
if (menus.indexOf(path) === -1) {
return <Redirect to="/" />
}
return Component && <Component {
...props} />
}}
/>
)
}
const mapStateToProps = (state) => {
return {
menus: state.LoginReducer.userInfo.authmenus,
}
}
export default connect(mapStateToProps, null)(ProtectedRoute)
学习更多
react学习地图