自入职以来,感觉生活着实是变得很忙碌,虽然是实习生,但工作依然是被安排的很充足。每天等着9点领完夜宵再下班已经是常态了,回到出租屋洗完澡已是10点,此后虽然还想着再学些什么却又更想还是看一会儿视频就睡觉好了。五一假期亦没有出行,一是没有想一起出游的伙伴,二是确实想好好休息下,与其出去受罪我还是想在学校歇着,玩一玩好久没动的游戏,看看书什么的。
说回此篇文章,在我实习经历中,我自己一直都在做的是类似于打杂的工作,主要时间都是在基于师兄建好的框架上进行页面的开发,虽然说在项目中这样的工作是占了绝大部分,但毫无疑问,那些前期基础的工作对于项目来说才是举足轻重的,是否掌握这些工程化的知识,也是区分前端工程师和前端切图仔的重要标准。出于掌握并分享知识的目的,我决定分为几个系列步骤,逐步搭建一个自己的React项目脚手架。
将axios根据业务的需求封装为对外暴露的request方法,整体代码还是比较简单明了的,这里就不再过多解释,代码中也有注释,其中还用到了一个decodehtml方法,是用来将后端返回的富文本错误信息进行展示。
/** decodeHtml */ export const decodeHtml = (html: string): string => { let oDiv = document.createElement('div'); oDiv.innerHTML = html; const textContent = oDiv.textContent; oDiv = null; return textContent; };
以下为request方法的代码(src/utils/request.ts)
import { Message, Dialog } from '@alifd/next'; import axios, { AxiosRequestConfig } from 'axios'; import { decodeHtml } from '@/utils'; export interface IRequest extends AxiosRequestConfig { url: string; /** 请求参数,当method为post的时候请使用data属性 */ params?: any; /** 当method为post的时候使用data属性 */ data?: any; /** * 是否缓存数据,相同url数据只请求一次,后面的请求都使用第一次请求的数据 */ cache?: boolean; /** 更据 cacheKey 进行缓存, 当cache 为true时生效 */ cacheKey?: string; /** * 错误时是否Message提示错误信息, 默认开启 */ enableErrorMsg?: boolean; // 缓存有效期 maxAge?: number; [key: string]: any; } // 缓存存储对象,当项目大了的时候考虑释放内存,目前不需要 const request_cache = {}; export interface IResult { success?: boolean; code?: string; message?: string; data?: any; [key: string]: any; } // 设置为ajax请求 axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; /** * 数据请求 * @example * request({ * url: '/a/b/c', * params: {} * }) * // res.success === true的时候执行 then * .then(res => {...}) * // res.success === false 的时候执行 catch * .catch(res => {...}) * * 请配合 `ahooks` 的 `useRequest` 使用 https://ahooks.js.org/hooks/async#dependent-request */ export default ({ cache = false, enableErrorMsg = true, cacheKey = '', maxAge = Infinity, //过期时间 ...params }: IRequest) => { // 本地缓存,只请求一次 if (cache && request_cache[`${params.url}-${cacheKey}`]) { if (request_cache[`${params.url}-${cacheKey}`].then) { return request_cache[`${params.url}-${cacheKey}`]; } else if ( new Date().getTime() - request_cache[`${params.url}-${cacheKey}`].cacheTime < maxAge ) { return new Promise(resolve => { resolve(request_cache[`${params.url}-${cacheKey}`].res); }); } } else if (request_cache[`${params.url}-${cacheKey}`]) { delete request_cache[`${params.url}-${cacheKey}`]; } if (params.method && params.method.toLowerCase() === 'post') { // post时传入参数是data字段 params.data = params.data || params.params || undefined; // params.data = qs.stringify(params.data); // 和后端约定 post请求用json的方式传递数据,所以关掉 params.params = undefined; params.headers = params.headers || { 'Content-Type': 'application/json;charset=UTF-8', // 和后端约定 post请求用json的方式传递数据 }; // 如果需要做csrf可以采用以下方案,需要后端先在接口返回信息中设置cookie // if (!isLocal()) { // const csrfToken = getCookie('XSRF-TOKEN'); // if (csrfToken) { // params.headers['X-XSRF-TOKEN'] = csrfToken; // } else { // Message.error('cookie获取失败'); // XSRF-TOKEN cookie 缺失 // throw new Error('cookie获取失败'); // } // } } else if ( !params.method || (params.method && params.method.toLowerCase() === 'get') ) { // get时传入的参数是params字段 params.params = params.params || params.data || undefined; } const servicePromise = new Promise((resolve, reject) => { axios(params) .then(({ data: res, status }: IResult) => { const { message, success, data, code } = res; if (success && status === 200) { // 成功 // 需要缓存的数据缓存下来 cache && (request_cache[`${params.url}-${cacheKey}`] = { res, cacheTime: new Date().getTime(), }); resolve(res); } else if (code === '9003') { // 状态过期重定向,后端code为9003,这里的code每个团队有自己的规范 Dialog.confirm({ content: `状态已过期,是否重新刷新页面? `, onOk: () => { window.location.reload(); }, }); } else if (data?.applyUrl) { // 临时处理无权限跳转 window.location.href = data.applyUrl; reject(res); } else { // 失败 // 失败时是否展示错误信息 enableErrorMsg && Message.error( `[${params.apiName || params.url}]: ${decodeHtml(message)}` ); reject(res); } }) .catch(e => { // 接口非200 || 接口非304 enableErrorMsg && Message.error(`[http]: ${e}`); reject(e); }); }); //缓存这里需要考虑一种情况是,在第二次请求发出时,第一次请求还未完成 //那么可以先把第一次请求操作缓存,第二次请求时判断若还在pending中,则返回promise对象,否则返回结果 if (cache) { request_cache[`${params.url}-${cacheKey}`] = servicePromise; } return servicePromise; };
应用中所有的请求方法都放在 src/services/ 目录下,每个模块/页面使用的请求方法放在一个对应的js/ts文件中。
//src/services/examplePage.ts import request from '@/utils/request'; export const exampleApi = ({ data, ...elseConfig }) => { return request({ url: `/api/reputation/evaluation/deepInsight/emotion`, method: 'post', data, ...elseConfig, }); };
在页面中使用,推荐搭配ahooks 的 useRequest使用
import {exampleApi} from '@/services/examplePage.ts'; import { useRequest } from 'ahooks'; const { data, error, loading } = useRequest(()=>exampleApi({ data:{ yourInfo:'' }, cache:true, maxAge:360000 });
作者:羽晋
链接:https://juejin.cn/post/6957945548607324191
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。