react笔记(二十一)—— 非组件获取路由信息

434 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情

前言

大家好呀,我是L同学。在上篇文章react笔记(二十)—— 配置路径别名中,我们学习了配置路径别名、@别名路径提示、通过redux实现登录功能等相关知识点。在本篇文章中,我们将学习到项目中经常用到的知识点,包括非组件获取路由信息、路由鉴权等相关知识点。

非组件获取路由信息

在项目中我们经常在组件中进行路由跳转。所以我们在App.js中引入BrowserRouter、Route等信息,定义路由信息。

import {BrowserRouter as Router,  Route, Switch, Redirect} from 'react-router-dom'

function App() {
  return (
    <Router>
      <div className='app'>
      <Switch>
      <Redirect exact from='/' to="/home" ></Redirect>
        {/* <Route exact path='/' component={Layout}></Route> */}
        <Route path='/home' component={Layout}></Route>
        <Route path='/login' component={Login}></Route>
        <Route>
          <NotFound />
        </Route>
      </Switch>
      </div>
    </Router>
  )
}

然后在组件中通过使用useHistory进行路由跳转。

import { useHistory } from "react-router-dom"

...
const history = useHistory()
history.push('/home')

当处理token失效问题时,我们通常在响应拦截器中进行处理。当响应错误error.response.status为401时,通常进行如下操作: 提示用户登陆信息已过期、清除存储在redux和localstorage中的token、跳转到登录页。第一步和第二步处理是简单的,那么第三步我们怎么在非组件环境中拿到路由信息,进行相应的路由跳转等操作呢?

我们需要使用路由中提供的Router组件,并自定义history对象。

首先我们在utils文件夹中创建history.js文件,导入创建自定义history的函数。

import {createBrowserHistory} from 'history'
const history = createBrowserHistory()
export default history

然后,我们在App.jsh中导入Router组件,添加history属性。

import {Router, Redirect, Route, Switch} from 'react-router-dom'

然后在

import history from './utils/history'

function App() {
  return (
    <Router history={history}>
      <div className='app'>
      <Switch>
      <Redirect exact from='/' to="/home" ></Redirect>
        {/* <Route exact path='/' component={Layout}></Route> */}
        <Route path='/home' component={Layout}></Route>
        <Route path='/login' component={Login}></Route>
        <Route>
          <NotFound />
        </Route>
      </Switch>
      </div>
    </Router>
  )
}

这时,我们可以在非组件环境响应拦截器中使用自定义的history进行路由跳转。

在request.js文件中。

import { getToken } from './storage';
import store from '@/store'
import history from './history';

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
  // 对响应数据做点什么
  return response;
}, function (error) {
  // 对响应错误做点什么
  if(error.response.status === 401) {
    console.log('history', history);
    message.error('登录信息过期', 1)
    store.dispatch(logout())
    history.replace({
      pathname: '/login',
      state: {
        from: history.location.pathname
      }
    })
  }
  return Promise.reject(error);
});

路由鉴权

Route组件中,可以传component,代表对应的path渲染对应的组件。

<Route path="/login" component={Login}></Route>

除了传component,还可以传render,render接收一个函数。

<Route path="/login" render={() => <Login />}></Route>

还可以这样书写。

   <Route path='/home'>
          <Layout></Layout>
   </Route>

在pc端后台管理项目中,我们要进行登陆访问控制。若用户没有登陆(也就是没有token),是访问不了首页的。所以我们可以在render中进行条件判断。

当路径为/home时, 首先会判断是否有token, 有的话就渲染Layout组件,没有的话就重定向到登陆页面。

 <Route path='/home' render={() => {
          const token = getToken()
          if(token) {
            return <Layout /> 
          }else {
            return <Redirect to='/login'></Redirect> 
          }
        }}></Route>

我们可以封装自己的PrivateRoute组件。最后使用的时候跟Route组件一样的使用。

<PrivateRoute path="/home" component={Layout}></PrivateRoute>

或者这样使用。

 <PrivateRoute path="/home">
          <Layout></Layout>
</PrivateRoute>

首先,创建/component/PrivateRoute/index.js文件

import { getToken, hasToken } from '@/utils/storage'
import React from 'react'
import {Redirect, Route} from 'react-router-dom'

export default function PrivateRoute({children, component:Component, ...rest}) {
  return (
    <Route {...rest} render={() => {
      if(hasToken()) {
        return children ? children : <Component></Component>
      }else {
        return <Redirect to={{
          pathname: '/login'
        }}></Redirect>
      }
    }}></Route>
  )
}