React + 项目(从基础到实战) -- 第八期

ajax 请求的搭建

  1. 引入mock
  2. AP接口设计
  3. AJAX 通讯

前置知识

  • HTTP 协议 , 前后端通讯的桥梁
  • API : XMLHttpRequest 和 fetch
  • 常用工具axios

mock 引入

Mock.js (mockjs.com)

使用 mockJS

  1. 前端代码中引入 mockJs
  2. 定义要模拟的路由 , 返回结果
  3. mockJs 劫持ajax请求(返回模拟的结果)
ts 复制代码
import Mock from 'mockjs'

Mock.mock('/api/test', 'get', ()=>{

    return {

        code: 0,

        data: {

           name:"lxy text"

        }

    }

})

使用fetch api 向后端发起请求

ts 复制代码
 useEffect(()=>{

        fetch('/api/test')

        .then((res)=>{

            console.log("res = ",res)

        })

        .then((err)=>{

            console.log("err = ",err)

        })

  
  
  

    },[])

bug : 发现返回的数据不是我们模拟的

mockjs 劫持失败

因为mock JS 只能劫持XMLHttpRequest
使用axios(要先安装哦) axios中文文档|axios中文网 | axios (axios-js.com)

ts 复制代码
  axios.get('/api/test')

        .then(function (response) {

            console.log(response.data.data);

        })

        .catch(function (error) {

            console.log(error);

        });

成功

总结

  1. 只能劫持XMLHttpRequest 不能劫持fetch ,有局限性
  2. 注意线上环境要注释掉,否则线上请求也被劫持

前端项目中不建议使用 mock JS

node JS + mock JS

将mockJS 用于nodeJS服务端 , 使用它的Random能力

后端操作

  1. 初始化node 环境 npm init -y

  2. 安装mock JS

  3. 安装nodemon

    自定义启动命令

  4. 安装 koa
    Koa (koajs) -- 基于 Node.js 平台的下一代 web 开发框架 | Koajs 中文文档 (bootcss.com)

这里添加异步函数模拟请求响应的时间差

ts 复制代码
const Mock = require('mockjs');

  

const Random = Mock.Random;

  

module.exports = [

    {

        url: '/api/question/:id',

        method: 'get',

        response: () => {

            return {

                code: 200,

                data: {

                    id: Random.id(),

                    title: Random.ctitle()

                }

            }

        }

    },

    {

        url: '/api/question',

        method: 'post',

        response: () => {

            return {

                code: 200,

                data: {

                    id: Random.id(),

                    name: Random.cname(),

                }

            }

        }

    }

]
ts 复制代码
  

const Koa = require('koa');

const Router = require('koa-router');

const mockList = require('./mock/index');

  

const app = new Koa();

const router = new Router();

  

//定义异步函数

async function getRes(fn) {

    return new Promise(resolve => {

        setTimeout(() => {

           const res= fn()

           resolve(res)

        }, 2000)

    })

}

  
  

//注册 mock 路由

mockList.forEach(item => {

    const {url , method , response} = item;

    router[method](url, async ctx => {

        // const res=response();

        //模拟网络请求的加载状态, 2S

        const res = await getRes(response);

        ctx.body = res;

    })

})

  
  

app.use(router.routes());

app.listen(3001) // 监听的端口号

启动成功

localhost:3001/api/question/12

前端操作

ts 复制代码
  useEffect(()=>{

        // 跨域

        // > 前端地址:http://localhost:3000

        // > 后端地址:http://localhost:3001

     fetch('http://localhost:3001/api/test')

        .then((res)=>{

            console.log("res = ",res)

        })

        .then((err)=>{

            console.log("err = ",err)

        })

  

    },[])

跨域

前端地址:http://localhost:5173

后端地址:http://localhost:3001

解决vite的跨域问题_vite解决跨域-CSDN博客

发现还是报错

在后端改

在线mock平台

fast-mock y-api swagger

API 设计

用户API

  1. 登录
  2. 注册
  3. 获取用户信息

问卷api

  1. 创建问卷
  2. 获取单个问卷
  3. 更新问卷
  4. 删除问卷
  5. 查询问卷
  6. 复制问卷

使用Restful API

method: ,

path: ,

request body: ,

responde: ,

用户验证

JWT

统一返回格式

errno , data ,msg

实战

配置axios 基本功能

  1. 创建axios实例
  2. 配置全局的拦截器
ts 复制代码
import { message } from "antd";

import axios from "axios";

  

//1.创建实例

const instance = axios.create({

    baseURL: 'http://localhost:3001/api/',

    timeout: 1000,//等待一秒

    headers: {'X-Custom-Header': 'foobar'}

  });

  
  
  
  

//2.添加请求拦截器

instance.interceptors.request.use(function () {

    // 在发送请求之前做些什么

    console.log("我要发请求啦");

  }, function () {

    // 对请求错误做些什么

    console.log("请求错误啦");

  });

  

//3.添加响应拦截器

instance.interceptors.response.use(function (res) {

    // 2xx 范围内的状态码都会触发该函数。

    // 对响应数据做点什么

    console.log("我收到响应啦");

    const resData = (res.data || {}) as ResType;

    const {errno,data,msg} = resData;

    if(errno !== 0){

        message.error(msg || "未知错误");

    }

  

    return data as any;

  }, function () {

    // 超出 2xx 范围的状态码都会触发该函数。

    // 对响应错误做点什么

    console.log("响应错误啦");

  });

  
  

  //定义类型

type ResType={

    errno:number,

    data?:ResDataType,

    msg?:string

}

  

type ResDataType={

    [keu:string]: any //可以有任意值,只要key键是string类型

}

  
  
  
  
  

export default instance ;

模拟axios请求

请求函数

ts 复制代码
import axios , {ResDataType} from "./axios"

  

//获取单个问卷

export async function getQuestinService(id: string): Promise<ResDataType>{

    const url=`/question/${id}`

  

    const data = ( await axios.get(url) ) as ResDataType;

  

    return data;

}

使用

ts 复制代码
import React,{FC,useEffect} from 'react'

  

import {useParams} from 'react-router-dom';

  

//导入发起请求的函数

import { getQuestinService } from '../../../services/question';

  
  

const Edit : FC = ()=>{

    //获取携带的参数

    const {id = ''} = useParams();

    useEffect(()=>{

        getQuestinService(id);

    },[])

  

    return (

        <>

        <h1>edit  {id}</h1>

        {/* http://localhost:5173/question/edit/20 */}

        </>

    )

}



export default Edit;

报错

TypeError: Cannot read properties of undefined (reading 'cancelToken')
TypeError: Cannot read properties of undefined (reading 'cancelToken')_cannot read properties of undefined (reading 'canc-CSDN博客

又报错

message: 'timeout of 1000ms exceeded'

原来是前端设置了等待一秒,改一下

timeout: 1000 * 10,//等待10秒

页面添加loading效果

自定义

ts 复制代码
function useLoadQuestionData() {

    const {id = ''} =useParams()

    const [loading,setLoading] = useState(true)

    const [questionData,setQuestionData] = useState({})

  

    useEffect(()=>{

        async function fn()

        {

            const data = await getQuestinService(id)

            setQuestionData(data)

            setLoading(false)

        }

  

        fn()

    },[])

  

    return {loading,questionData}

  
  

}

使用ahooks中的useRequest

ts 复制代码
  async function load(){

        const data = await getQuestinService(id)

        return data;

    }

  

    const {loading,data,error} =useRequest(load)

  

    return {loading,data,error}

useRequest 与 自定义发请求

自定义请求

ts 复制代码
  const[questionList,setQuestionList] = useState([])

    const [total ,setTotal] =useState(0)

    useEffect(()=>{

      async function fn()

      {

          //问卷列表数据模拟

        const data= await getQuestinListService()

        const {list=[],total=0} =data

        setQuestionList(list)

        setTotal(total)

     }

     fn()

    },[])

使用useRequest

ts 复制代码
 const {data={},loading} = useRequest(getQuestinListService)

    const {list=[],total=0} = data

列表增加搜索hook

向后端发起请求的接口

ts 复制代码
//获取(搜索)问卷列表

export async function getQuestinListService(

    opt:Partial<SearchType>

): Promise<ResDataType>{

    const url='/question'

    const data = ( await axios.get(url,{

        params:opt

    }) ) as ResDataType;

    return data;

}

自定义hook

ts 复制代码
import {LIST_SEARCH_PARAM_KEY} from "../constant/index";

import {  useSearchParams } from "react-router-dom";

import { useRequest } from "ahooks";

//导入发起请求的函数

  

import { getQuestinListService } from "../services/question";

  

function useLoadQuestionData() {

    const [searchParams] = useSearchParams();

  
  

    async function load(){

        const keyword=searchParams.get(LIST_SEARCH_PARAM_KEY) || " "

        const data = await getQuestinListService({keyword});

  

        return data;

    }

  

    const {loading,data,error} =useRequest(load,{

        refreshDeps:[searchParams],//刷新的依赖项

    })

  

    return {loading,data,error}

  
  

}

  
  

export default useLoadQuestionData;

使用自定义hook重构list,Star,Trash页面,向后端发请求

发现星标页面并未实现真的搜索功能

因为后端是随机生成的

解决

相关推荐
南城书生6 小时前
Android Handler 机制源码分析
前端
南城书生6 小时前
Android 大图加载与 OOM 优化
前端
南城书生6 小时前
RecyclerView 源码分析
前端
南城书生6 小时前
LeakCanary 原理分析
前端
没想好d6 小时前
通用管理后台组件库-13-页签组件
前端
xChive6 小时前
ECharts-大屏开发复习记录与踩坑总结
前端·javascript·echarts
南城书生6 小时前
Java HashMap 源码分析
前端
南城书生6 小时前
Java 线程池(ThreadPoolExecutor)源码分析
前端
前端Hardy6 小时前
别再靠 Code Review 纠格式了!一套自动化前端工程化方案,让 Vue 项目提交即合规
前端·程序员·代码规范
前端Hardy6 小时前
用 uni-app x 重构我们的 App:一套代码跑通 iOS、Android、鸿蒙!人力成本直降 60%
前端·ios·uni-app