react学习:react-router路由

问题导向

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个属性:

  • history:用来做命令式导航
  • location:当前的URL信息
  • match:用来获取参数信息

用法

第一种:
<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
区别

  1. 类型:component是组件,children和render是函数
  2. 优先级:children最高,其次component,最后render
  3. 匹配方式:
  1. children不管路由是否匹配,都会渲染
  2. component路由匹配才会渲染,源码使用createElement,如果使用component={() => },会不匹配,造成先卸载再挂载,浪费性能,如果需要这种方式,可用render替代
  3. 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学习地图

你可能感兴趣的:(react,reactjs)