前端实战|React18极客园——布局模块(useRoutes路由配置处理Token失效退出登录)
Posted codeMak1r.小新
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端实战|React18极客园——布局模块(useRoutes路由配置处理Token失效退出登录)相关的知识,希望对你有一定的参考价值。
欢迎来到我的博客
📔博主是一名大学在读本科生,主要学习方向是前端。
🍭目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
🛠目前正在学习的是🔥 R e a c t / 小程序 React/小程序 React/小程序🔥,中间穿插了一些基础知识的回顾
🌈博客主页👉codeMak1r.小新的博客😇本文目录😇
本文被专栏【React–从基础到实战】收录
🕹坚持创作✏️,一起学习📖,码出未来👨🏻💻!
最近在学习React过程中,找到了一个实战小项目,在这里与大家分享。
本文遵循项目开发流程,逐步完善各个需求
gitee完整项目地址:极客园完整代码
Layout模块
1. 基本结构搭建
本节目标:
能够使用antd搭建基础布局
实现步骤
- 打开 antd/Layout 布局组件文档,找到示例:顶部-侧边布局-通栏
- 拷贝示例代码到我们的 Layout 页面中
- 分析并调整页面布局
代码实现
pages/Layout/index.js
import Layout, Menu, Popconfirm from 'antd'
import
HomeOutlined,
DiffOutlined,
EditOutlined,
LogoutOutlined
from '@ant-design/icons'
import './index.scss'
const Header, Sider = Layout
const GeekLayout = () =>
return (
<Layout>
<Header className="header">
<div className="logo" />
<div className="user-info">
<span className="user-name">user.name</span>
<span className="user-logout">
<Popconfirm title="是否确认退出?" okText="退出" cancelText="取消">
<LogoutOutlined /> 退出
</Popconfirm>
</span>
</div>
</Header>
<Layout>
<Sider width=200 className="site-layout-background">
<Menu
mode="inline"
theme="dark"
defaultSelectedKeys=['1']
style= height: '100%', borderRight: 0
>
<Menu.Item icon=<HomeOutlined /> key="1">
数据概览
</Menu.Item>
<Menu.Item icon=<DiffOutlined /> key="2">
内容管理
</Menu.Item>
<Menu.Item icon=<EditOutlined /> key="3">
发布文章
</Menu.Item>
</Menu>
</Sider>
<Layout className="layout-content" style= padding: 20 >内容</Layout>
</Layout>
</Layout>
)
export default GeekLayout
pages/Layout/index.scss
.ant-layout
height: 100%;
.header
padding: 0;
.logo
width: 200px;
height: 60px;
background: url('~@/assets/logo.png') no-repeat center / 160px auto;
.layout-content
overflow-y: auto;
.user-info
position: absolute;
right: 0;
top: 0;
padding-right: 20px;
color: #fff;
.user-name
margin-right: 20px;
.user-logout
display: inline-block;
cursor: pointer;
.ant-layout-header
padding: 0 !important;
2. 二级路由配置
本节目标:
能够在右侧内容区域展示左侧菜单对应的页面内容
使用步骤
- 在 pages 目录中,分别创建:Home(数据概览)/Article(内容管理)/Publish(发布文章)页面文件夹
- 分别在三个文件夹中创建 index.js 并创建基础组件后导出
- 在app.js中配置嵌套子路由,在layout.js中配置二级路由出口
- 使用 Link 修改左侧菜单内容,与子路由规则匹配实现路由切换
代码实现
pages/Home/index.js
const Home = () =>
return <div>Home</div>
export default Home
pages/Article/index.js
const Article = () =>
return <div>Article</div>
export default Article
pages/Publish/index.js
const Publish = () =>
return <div>Publish</div>
export default Publish
src/routes/index.js
export default [
// 不需要鉴权的组件Login
path: "/login",
element: <Login />
,
// 需要鉴权的组件Layout
path: "/",
element: <AuthRoute>
<Layout />
</AuthRoute>,
children: [
path: "home",
element: <AuthRoute>
<Home />
</AuthRoute>
,
path: "article",
element: <AuthRoute>
<Article />
</AuthRoute>
,
path: "publish",
element: <AuthRoute>
<Publish />
</AuthRoute>
,
path: "",
element: <Navigate to="home" replace />
]
]
pages/Layout/index.js
// 配置Link组件
<Menu
mode="inline"
theme="dark"
defaultSelectedKeys=['1']
style= height: '100%', borderRight: 0
>
<Menu.Item icon=<HomeOutlined /> key="1" onClick=() => navigate('home')>
数据概览
</Menu.Item>
<Menu.Item icon=<DiffOutlined /> key="2" onClick=() => navigate('article')>
内容管理
</Menu.Item>
<Menu.Item icon=<EditOutlined /> key="3" onClick=() => navigate('publish')>
发布文章
</Menu.Item>
</Menu>
<Layout className="layout-content" style= padding: 20 ><Outlet /></Layout>
3. 菜单高亮显示
本节目标:
能够在页面刷新的时候保持对应菜单高亮
思路
- Menu组件的selectedKeys属性与Menu.Item组件的key属性发生匹配的时候,Item组件即可高亮
- 页面刷新时,将
当前访问页面的路由地址
作为 Menu 选中项的值(selectedKeys)即可
实现步骤
- 将 Menu 的
key
属性修改为与其对应的路由地址 - 获取到当前正在访问页面的路由地址
- 将当前路由地址设置为
selectedKeys
属性的值
代码实现
pages/Layout/index.js
import useLocation from 'react-router-dom'
const GeekLayout = () =>
const pathname: selectedKey = useLocation()
console.log(selectedKey)
return (
// ...
<Menu
mode="inline"
theme="dark"
selectedKeys=[selectedKey]
style= height: '100%', borderRight: 0
>
<Menu.Item icon=<HomeOutlined /> key="/home" onClick=() => navigate('home')>
数据概览
</Menu.Item>
<Menu.Item icon=<DiffOutlined /> key="/article" onClick=() => navigate('article')>
内容管理
</Menu.Item>
<Menu.Item icon=<EditOutlined /> key="/publish" onClick=() => navigate('publish')>
发布文章
</Menu.Item>
</Menu>
)
4. 展示个人信息
本节目标:
能够在页面右上角展示登录用户名
实现步骤
- 在store中新增user.Store.js模块,在其中定义获取用户信息的mobx代码
- 在store的入口文件中组合新增的userStore模块
- 在Layout组件中调用action函数获取用户数据
- 在Layout组件中获取个人信息并展示
代码实现
store/user.Store.js
// 用户模块
import makeAutoObservable from "mobx"
import http from '@/utils'
class UserStore
userInfo =
constructor()
makeAutoObservable(this)
async getUserInfo()
const res = await http.get('/user/profile')
this.userInfo = res.data
export default UserStore
store/index.js
import React from "react"
import LoginStore from './login.Store'
import UserStore from './user.Store'
class RootStore
// 组合模块
constructor()
this.loginStore = new LoginStore()
this.userStore = new UserStore()
const StoresContext = React.createContext(new RootStore())
export const useStore = () => React.useContext(StoresContext)
pages/Layout/index.js
import useEffect from 'react'
import observer from 'mobx-react-lite'
const GeekLayout = () =>
const userStore = useStore()
// 获取用户数据
useEffect(() =>
try
userStore.getUserInfo()
catch
, [userStore])
return (
<Layout>
<Header className="header">
<div className="logo" />
<div className="user-info">
<span className="user-name">userStore.userInfo.name</span>
</div>
</Header>
/* 省略无关代码 */
</Layout>
)
export default observer(GeekLayout)
5. 退出登录实现
本节目标:
能够实现退出登录功能
实现步骤
- 为气泡确认框添加确认回调事件
- 在
store/login.Store.js
中新增退出登录的action函数,在其中删除token - 在回调事件中,调用loginStore中的退出action
- 退出后,返回登录页面
代码实现
store/login.Store.js
class LoginStore
// 退出登录
loginOut = () =>
this.token = ''
clearToken()
export default LoginStore
clearToken()是utils/token.js中定义好的清除token的工具函数。
pages/Layout/index.js
// login out
const navigate = useNavigate()
const onLogout = () =>
loginStore.loginOut()
navigate('/login')
<span className="user-logout">
<Popconfirm title="是否确认退出?" okText="退出" cancelText="取消" onConfirm=onLogout>
<LogoutOutlined /> 退出
</Popconfirm>
</span>
6. 处理Token失效
本节目标:
能够在响应拦截器中处理token失效
说明:为了能够在非组件环境下拿到路由信息,需要我们安装一个history包
实现步骤
- 安装history包:
yarn add history
- 创建
utils/history.js
文件 - 在app.js中使用我们新建的路由并配置history参数
- 通过响应拦截器处理 token 失效,如果发现是401跳回到登录页
代码实现
utils/history.js
// https://github.com/remix-run/react-router/issues/8264
import createBrowserHistory from 'history'
const history = createBrowserHistory()
export history
index.js入口文件
...省略无关代码
import unstable_HistoryRouter as HistoryRouter from "react-router-dom";
import history from "./utils/history";
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<HistoryRouter history=history>
<App />
</HistoryRouter>
)
utils/http.js
import history from './history'
http.interceptors.response.use(
response =>
return response.data
,
error =>
if (error.response.status === 401)
// 清除失效的token
removeToken()
// 跳转到登录页
history.push('/login')
return Promise.reject(error)
)
7. 首页Home图表展示
本节目标:
实现首页echart图表封装展示
需求描述:
- 使用eharts配合react封装柱状图组件Bar
- 要求组件的标题title,横向数据xData,纵向数据yData,样式style可定制
代码实现
components/Bar/index.js
// 封装图表bar组件
// 思路:
// 1. 看官方文档 把echarts加入项目
// 如何在react中获取dom => useRef
// 在什么地方获取dom节点 => useEffect
// 2. 不抽离定制化参数 先把最小化的demo跑起来
// 3. 按照需求:哪些参数需要自定义 抽象出来
import useRef, useEffect from 'react';
import * as echarts from 'echarts'
export default function Bar( title, xData, yData, style )
const domRef = useRef()
// 执行这个初始化的函数
useEffect(() =>
const chartInit = () =>
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(domRef.current);
// 绘制图表
myChart.setOption(
title:
text: title
,
tooltip: ,
xAxis:
data: xData
,
yAxis: ,
series: [
name: '框架',
type: 'bar',
data: yData
]
);
chartInit()
, [title, xData, yData])
return (
<div>
/* 为echart准备一个dom节点 */
<div ref=domRef style=style></div>
</div>
)
pages/Home/index.js
import React from 'react'
import Bar from '@/components/Bar'
export default function Home()
return (
<div>
<Bar
title='主流框架使用满意度'
xData=['React', 'Vue', 'Angular']
yData=[40, 50, 30]
style= width: '500px', height: '400px'
/>
<Bar
title='主流框架使用满意度2'
xData=['React', 'Vue', 'Angular']
yData=[70, 80, 40]
style= width: '300px', height: '200px'
/>
</div>
)
pages/Home/index.scss
.home
width: 100%;
height: 100%;
align-items: center;
下篇文章:内容管理模块的实现
专栏订阅入口【React–从基础到实战】
以上是关于前端实战|React18极客园——布局模块(useRoutes路由配置处理Token失效退出登录)的主要内容,如果未能解决你的问题,请参考以下文章