前端实战|React18极客园——登陆模块(token持久化、路由拦截、mobx、封装axios)

news2025/2/24 7:13:07

在这里插入图片描述

欢迎来到我的博客
📔博主是一名大学在读本科生,主要学习方向是前端。
🍭目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
🛠目前正在学习的是🔥 R e a c t 框架 React框架 React框架🔥,中间穿插了一些基础知识的回顾
🌈博客主页👉codeMak1r.小新的博客

😇本文目录😇

  • 登陆模块
    • 1.基本结构模块
    • 2. 创建表单结构
    • 3. 表单校验实现
    • 4. 获取登录表单数据
    • 5. 封装http工具模块
    • 6. 配置登录Mobx
    • 7. 实现登录逻辑
    • 8. token持久化
      • 封装工具函数
      • 持久化设置
    • 9. axios请求拦截器注入token
    • 10. 路由导航守卫

本文被专栏【React–从基础到实战】收录
🕹坚持创作✏️,一起学习📖,码出未来👨🏻‍💻!

最近在学习React过程中,找到了一个实战小项目,在这里与大家分享。
本文遵循项目开发流程,逐步完善各个需求
前文——《项目前置准备》

登陆模块

1.基本结构模块

本节目标: 能够使用antd搭建基础布局

实现步骤

  1. 在 Login/index.js 中创建登录页面基本结构
  2. 在 Login 目录中创建 index.scss 文件,指定组件样式
  3. 将 logo.png 和 login.png 拷贝到 assets 目录中

代码实现

pages/Login/index.js

import { Card } from 'antd'
import logo from '@/assets/logo.png'
import './index.scss'

const Login = () => {
  return (
    <div className="login">
      <Card className="login-container">
        <img className="login-logo" src={logo} alt="" />
        {/* 登录表单 */}
      </Card>
    </div>
  )
}

export default Login

pages/Login/index.scss

.login {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  background: center/cover url('~@/assets/login.png');
  
  .login-logo {
    width: 200px;
    height: 60px;
    display: block;
    margin: 0 auto 20px;
  }
  
  .login-container {
    width: 440px;
    height: 360px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 50px rgb(0 0 0 / 10%);
  }
  
  .login-checkbox-label {
    color: #1890ff;
  }
}

2. 创建表单结构

本节目标: 能够使用antd的Form组件创建登录表单

实现步骤

  1. 打开 antd Form 组件文档
  2. 找到代码演示的第一个示例(基本使用),点击<>(显示代码),并拷贝代码到组件中
  3. 分析 Form 组件基本结构
  4. 调整 Form 组件结构和样式

代码实现

pages/Login/index.js

import { Form, Input, Button, Checkbox } from 'antd'
const Login = () => {
  return (
    <Form>
      <Form.Item>
        <Input size="large" placeholder="请输入手机号" />
      </Form.Item>
      <Form.Item>
        <Input size="large" placeholder="请输入验证码" />
      </Form.Item>
      <Form.Item>
        <Checkbox className="login-checkbox-label">
          我已阅读并同意「用户协议」和「隐私条款」
        </Checkbox>
      </Form.Item>

      <Form.Item>
        <!-- 渲染Button组件为submit按钮 -->
        <Button type="primary" htmlType="submit" size="large" block>
          登录
        </Button>
      </Form.Item>
    </Form>
  )
}

3. 表单校验实现

本节目标: 能够为手机号和密码添加表单校验

实现步骤

  1. 为 Form 组件添加 validateTrigger 属性,指定校验触发时机的集合
  2. 为 Form.Item 组件添加 name 属性,这样表单校验才会生效
  3. 为 Form.Item 组件添加 rules 属性,用来添加表单校验

代码实现

page/Login/index.js

const Login = () => {
  return (
    <Form validateTrigger={['onBlur', 'onChange']}>
      <Form.Item
        name="mobile"
        rules={[
          {
            pattern: /^1[3-9]\d{9}$/,
            message: '手机号码格式不对',
            validateTrigger: 'onBlur'
          },
          { required: true, message: '请输入手机号' }
        ]}
      >
        <Input size="large" placeholder="请输入手机号" />
      </Form.Item>
      <Form.Item
        name="code"
        rules={[
          { len: 6, message: '验证码6个字符', validateTrigger: 'onBlur' },
          { required: true, message: '请输入验证码' }
        ]}
      >
        <Input size="large" placeholder="请输入验证码" maxLength={6} />
      </Form.Item>
      <Form.Item name="remember" valuePropName="checked">
        <Checkbox className="login-checkbox-label">
          我已阅读并同意「用户协议」和「隐私条款」
        </Checkbox>
      </Form.Item>

      <Form.Item>
        <Button type="primary" htmlType="submit" size="large" block>
          登录
        </Button>
      </Form.Item>
    </Form>
  )
}

4. 获取登录表单数据

本节目标: 能够拿到登录表单中用户的手机号码和验证码

实现步骤

  1. 为 Form 组件添加 onFinish 属性,该事件会在点击登录按钮时触发
  2. 创建 onFinish 函数,通过函数参数 values 拿到表单值
  3. Form 组件添加 initialValues 属性,来初始化表单值

代码实现

pages/Login/index.js

// 点击登录按钮时触发 参数values即是表单输入数据
const onFinish = values => {
  console.log(values)
}

<Form
  onFinish={ onFinish }
  initialValues={{
    mobile: '13911111111',
    code: '246810',
    remember: true
  }}
>...</Form>

5. 封装http工具模块

本节目标: 封装axios,简化操作

实现步骤

  1. 创建 utils/http.js 文件
  2. 创建 axios 实例,配置 baseURL,请求拦截器,响应拦截器
  3. 在 utils/index.js 中,统一导出 http

代码实现

utils/http.js

import axios from 'axios'

const http = axios.create({
  baseURL: 'http://geek.itheima.net/v1_0',
  timeout: 5000
})
// 添加请求拦截器
http.interceptors.request.use((config)=> {
    return config
  }, (error)=> {
    return Promise.reject(error)
})

// 添加响应拦截器
http.interceptors.response.use((response)=> {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response
  }, (error)=> {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error)
})

export { http }

utils/index.js

import { http } from './http'
export {  http }

6. 配置登录Mobx

本节目标: 基于mobx封装管理用户登录的store

store/login.Store.js

// 登录模块
import { makeAutoObservable } from "mobx"
import { http } from '@/utils'

class LoginStore {
  token = ''
  constructor() {
    makeAutoObservable(this)
  }
  // 登录
  login = async ({ mobile, code }) => {
    const res = await http.post('http://geek.itheima.net/v1_0/authorizations', {
      mobile,
      code
    })
    this.token = res.data.token
  }
}
export default LoginStore

store/index.js

import React from "react"
import LoginStore from './login.Store'

class RootStore {
  // 组合模块
  constructor() {
    this.loginStore = new LoginStore()
  }
}
// 导入useStore方法供组件使用数据
const StoresContext = React.createContext(new RootStore())
export const useStore = () => React.useContext(StoresContext)

7. 实现登录逻辑

本节目标: 在表单校验通过之后通过封装好的store调用登录接口

实现步骤

  1. 使用useStore方法得到loginStore实例对象
  2. 在校验通过之后,调用loginStore中的login函数
  3. 登录成功之后跳转到首页

代码实现

import { useStore } from '@/store'
const onFinish = async (values) => {
    // 存储登录成功的token
    try {
      await loginStore.setToken(values)
      navigate('/', { replace: true })
      message.success('At Your Service, Sir!', 2)
    } catch (error) {
      message.error(error.response?.data?.message || '登录失败')
    }
  };
  const onFinishFailed = (errorInfo) => {
    const [name] = errorInfo.errorFields[0].name
    if (name === "captcha") message.error('登录失败,请检查验证码是否有误!', 2);
    if (name === "tel") message.error('登录失败,请检查手机号是否有误!', 2);
  }
  return (...)
}

8. token持久化

封装工具函数

本节目标: 能够统一处理 token 的持久化相关操作,确保刷新后 token 不丢失。

实现步骤

  1. 创建 utils/token.js 文件
  2. 分别提供 getToken/setToken/clearToken/isAuth 四个工具函数并导出
  3. 创建 utils/index.js 文件,统一导出 token.js 中的所有内容,来简化工具函数的导入
  4. 将登录操作中用到 token 的地方,替换为该工具函数

代码实现

utils/token.js

const TOKEN_KEY = 'geek_pc'

const getToken = () => localStorage.getItem(TOKEN_KEY)
const setToken = token => localStorage.setItem(TOKEN_KEY, token)
const clearToken = () => localStorage.removeItem(TOKEN_KEY)

export { getToken, setToken, clearToken }

持久化设置

本节目标: 使用token函数持久化配置

实现步骤

  1. 拿到token的时候一式两份,存本地一份
  2. 初始化的时候优先从本地取,取不到再初始化为控制

代码实现

store/login.Store.js

// 登录模块
import { makeAutoObservable } from "mobx"
import { setToken, getToken, clearToken, http } from '@/utils'

class LoginStore {
  // 这里哦!!
  token = getToken() || ''
  constructor() {
    makeAutoObservable(this)
  }
  // 登录
  login = async ({ mobile, code }) => {
    const res = await http.post('http://geek.itheima.net/v1_0/authorizations', {
      mobile,
      code
    })
    this.token = res.data.token
    // 还有这里哦!!
    setToken(res.data.token)
  }
 
}
export default LoginStore

9. axios请求拦截器注入token

《Vue/React项目实现axios请求拦截器注入token》

本节目标: 把token通过请求拦截器注入到请求头中

img

拼接方式:config.headers.Authorization = Bearer ${token}}

utils/http.js

http.interceptors.request.use(config => {
  const token = getToken('pc-key')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

第一次发起请求,是登录请求,此时,localStorage中没有token,getToken获取不到,不走下面这个if函数体,直接return config;

后面再发请求时,由于已经登录了,此时,localStorage中有token,getToken获取到了,走if中的函数体,在发起请求前自动进行预处理,追加一个token,以便于访问需要权限的页面

为请求头对象(headers)中添加token验证的自定义字段(Authorization),作用是为了让需要验证才能使用的API能够使用(请求头中携带了token值则可通过验证)

在最后必须return config

10. 路由导航守卫

【Vue/React实现路由鉴权/导航守卫/路由拦截(react-router v6)】

本节目标: 能够实现未登录时访问拦截并跳转到登录页面(路由鉴权实现)

实现思路

自己封装 AuthRoute 路由鉴权高阶组件,实现未登录拦截,并跳转到登录页面

思路为:判断本地是否有token,如果有,就返回子组件,否则就重定向到登录Login

实现步骤

  1. 在 components 目录中,创建 AuthRoute/index.js 文件
  2. 判断是否登录
  3. 登录时,直接渲染相应页面组件
  4. 未登录时,重定向到登录页面
  5. 将需要鉴权的页面路由配置,替换为 AuthRoute 组件渲染

代码实现

components/AuthRoute/index.js

// 路由鉴权
// 1. 判断token是否存在
// 2. 如果存在 直接正常渲染
// 3. 如果不存在 重定向到登录路由

import { Navigate } from "react-router-dom";
import { getToken } from "@/utils";
// 高阶组件:把一个组件当成另外一个组件的参数传入 然后通过一定的判断 返回新的组件
// 这里的AuthRoute就是一个高阶组件

function AuthRoute({ children }) {
  // 获取token
  const tokenStr = getToken()
  // 如果token存在 直接正常渲染
  if (tokenStr) {
    return <>{children}</>
  }
  // 如果token不存在,重定向到登录路由
  else {
    return <Navigate to='/login' replace />
  }
}
{/*
 <AuthRoute> <Layout /> </AuthRoute> 
 登录:<> <Layout /> </>
 非登录:<Navigate to="/login" replace />
*/ }
export { AuthRoute }

注:utils工具函数getToken如下

// 从localstorage中取token
const getToken = () => {
return window.localStorage.getItem(key)
}

src/routes/index.js路由表文件

import Layout from "@/pages/Layout";
import Login from "@/pages/Login";
import { AuthRoute } from "@/components/AuthRoute";

// eslint-disable-next-line
export default [
  // 不需要鉴权的组件Login
  {
    path: "/login",
    element: <Login />
  },
  // 需要鉴权的组件Layout
  {
    path: "/",
    element: <AuthRoute>
      <Layout />
    </AuthRoute>
  }
]

下篇文章:Layout布局模块的实现
专栏订阅入口【React–从基础到实战】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vite搭建vue2项目

问题提出 最近在做一个练习的小项目&#xff0c;由于要配合组成员的其它成员来搭建项目&#xff0c;大多掌握的技术栈都在vue2&#xff0c;用惯了vite来搭建&#xff08;vite真香~&#xff09;,就想着来搭建一个vue2的项目。原本以为查下百度很快可以搭好&#xff0c;没想到折…

【小程序从0到1】WXSS模版语法汇总

欢迎来到我的博客 &#x1f4d4;博主是一名大学在读本科生&#xff0c;主要学习方向是前端。 &#x1f36d;目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏 &#x1f6e0;目前正在学习的是&#x1f525;React/小程序React/小程序React/小程序&am…

微前端vue项目实战 -- 乾坤qiankun框架 (一)

背景&#xff1a; 公司研发的项目主要是 GIS地图为基础的管理系统&#xff0c;由主体项目&#xff08;管理业务模块&#xff09; GIS地图应用&#xff0c;由于 GIS地图应用模块 会在多个地方使用&#xff0c;所以单独构建一个项目&#xff0c;分别在不同的业务场景中引用、交互…

JavaScript鼠标移动事件及案例

一、鼠标点击事件 1.onclick单击事件 鼠标单击时事件处理函数 <input type"button" id"bt" value"点击"> <script> //找到按钮并设置点击事件 document.getElementById("bt").onclick function (){ //被点击…

kkFileView部署及使用

Windows:kkFileView部署及使用前言部署Web引用普通webVue &#xff1a;需要引入base64.js前言 kkFileView支持主流文档的在线预览服务。官网地址 部署 kkFileView不需要集成&#xff0c;只需要部署到服务器即可。 从 Gitee 上下载最新的压缩包&#xff0c;或者从代码仓库中下…

【Vue+element-ui搭建前端页面】适用于初学者学习

作者有话说&#xff1a; 学习编程我们必不可少的就是做项目&#xff0c;在学习后端的同时&#xff0c;前端知识也是要学习滴&#xff0c;这篇文章将展示如何利用Vue和element-ui搭建前端界面。话不多说&#xff0c;进入主题&#xff01;&#xff01;&#xff01; 目录 首先是…

网页报错“Form elements must have labels”的处理

网页报错“Form elements must have labels”的处理 先给出错误现象源码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width&quo…

uniapp中单选按钮的实现

标签说明&#xff1a; radio-group&#xff1a;单项选择器&#xff0c;内部由多个 <radio> 组成。通过把多个radio包裹在一个radio-group下&#xff0c;实现这些radio的单选。 radio&#xff1a;单选项目 属性说明&#xff1a; change&#xff1a;<radio-group>…

Vue中使用element-ui 给按钮绑定一个单击事件,实现点击按钮就弹出一个dialog对话框

1.需求描述 想要实现点击一个按钮就弹出一个对话框&#xff0c;在对话框中可输入数据进行提交&#xff0c;在点击取消时对话框关闭 2.功能实现 1.创建按钮 在element中把找到按钮的代码放到div里 <el-row><el-button type"primary" plain>新增</el…

Java支付宝沙箱环境支付,SDK接口远程调试【内网穿透】

文章目录1.测试环境2.本地配置3. 内网穿透3.1 下载安装cpolar内网穿透3.2 创建隧道4. 测试公网访问5. 配置固定二级子域名5.1 保留一个二级子域名5.2 配置二级子域名6. 使用固定二级子域名进行访问1.测试环境 MavenSpring bootJdk 1.8 2.本地配置 获取支付宝支付Java SDK,ma…

Vue--》过滤器介绍及其使用方法

目录 过滤器 过滤器的兼容性 私有过滤器和全局过滤器 过滤器的连续调用 过滤器进行传参 过滤器 过滤器的兼容性 注意&#xff1a;Vue3中明确取消了过滤器这个功能&#xff0c;如果想使用只能在Vue2中进行&#xff0c;如果所做的项目是Vue2的话&#xff0c;可以了解一下这…

uni-app开发微信小程序,H5 关于压缩上传图片的问题

文章目录 前言 一、为什么要压缩图片 二、图片压缩方式 1. 微信小程序​​​​​​​ 2. H5 总结 前言 关于微信小程序、H5兼容性问题&#xff0c;今天就压缩以及上传图片做一个可实现方法的简要阐述。 一、为什么要压缩图片​​​​​​​ 在使用uni-app开发小程序及H…

深入了解-微信开发者工具

主要介绍微信开发者工具如何编译小程序代码&#xff0c;如何实现小程序模拟器以及如何调试小程序。 1 简介 虽然在开发语言层面小程序与传统的网页差别不大&#xff1a;是使用JavaScript 脚本语言编写逻辑代码、使用类似于HTML的WXML来描述页面的结构、使用类似于CSS的WXSS来…

B/S架构

目录 一、什么是B/S架构 二、三层架构 三、Active技术 四、网络节点 五、分布式网络计算 六、JavaScript 一、什么是B/S架构 1.B/S架构是软件系统体系结构&#xff0c;是指浏览器-Web服务器(Broswer-Server)&#xff0c;采用三层架构&#xff0c;即表现层、业务逻辑层、数据访问…

十分钟带你入门Chrome插件开发

一、简述 我们所说的chrome插件一般都是指chrome扩展程序&#xff08;Chrome Extension&#xff09;。chrome插件是一个用Web技术开发、用来增强浏览器功能的软件&#xff0c;它其实就是一个由HTML、CSS、JS、图片等资源组成的一个.crx后缀的文件。chrome插件除了Chrome浏览器…

【TFS-CLUB社区 第4期赠书活动】〖Flask Web全栈开发实战〗等你来拿,参与评论,即可有机获得

文章目录❤️‍&#x1f525; 赠书活动 - 《Flask Web全栈开发实战》❤️‍&#x1f525; 编辑推荐❤️‍&#x1f525; 内容提要❤️‍&#x1f525; 赠书活动 → 获奖名单❤️‍&#x1f525; 赠书活动 - 《Flask Web全栈开发实战》 内容简介&#xff1a; 《Flask Web全栈开发…

flex布局 多种方法让两个盒子分布在左右两边

方法一&#xff1a; 一个父盒子里面包含了两个子盒子的&#xff0c;可以用justify-content:space-between属性 <div classparent> <div class"left"></div> <div class"right"></div> </div> .parent { disp…

FreeRTOS(教程非常详细)

概述&#xff1a; 之前写了关于FreeRTOS的部分内容&#xff0c;为了方便阅读&#xff0c;现在给汇总到一起了。全部学习完后&#xff0c;恭喜你对FreeRTOS有了更深的认知。 第一章 FreeRTOS移植到STM32 第二章 FreeRTOS创建任务 第三章 FreeRTOS任务管理 第四章 FreeRTOS消…

【springcloud 微服务】Spring Cloud Ribbon 负载均衡使用策略详解

目录 一、前言 二、什么是Ribbon 2.1 ribbon简介 2.1.1 ribbon在负载均衡中的角色 2.2 客户端负载均衡 2.3 服务端负载均衡 2.4 常用负载均衡算法 2.4.1 随机算法 2.4.2 轮询算法 2.4.3 加权轮询算法 2.4.4 IP地址hash 2.4.5 最小链接数 三、Ribbon中负载均衡策略…

Unity 实现A* 寻路算法

前言 A* 寻路算法是什么 游戏开发中往往有这样的需求&#xff0c;让玩家控制的角色自动寻路到目标地点&#xff0c;或是让 AI 角色移动到目标位置&#xff0c;实际的情况可能很复杂&#xff0c;比如地图上有无法通过的障碍或者需要付出代价&#xff08;时间或其他资源&#x…