解决复用页面只是接口不同的问题的完整指南

🔥 前言

最近遇到一个需求,需要复用原来的组件页面(页面比较复杂涉及很多弹窗操作,表单和二级详情页),新旧页面组件只是调用接口不同,新旧两套接口,其他只是略微文案上的差异。后期的话新页面肯定会有较大变动,业务着急所以临时复用旧页面。

🤔 问题描述

由于后面可能会有较大变动,这期新加复用页面也可能会下掉,如何有效的修改,并且确保后续下掉这期功能不会影响旧原来功能;

如何能做到更方便下掉这期功能删除代码,且不会影响原来的功能逻辑?

💡 解决方案

假设新增的组件是B,需要引用原来的组件A。

方案一:使用useContext

代码示例

javascript 复制代码
const apiMapA = {
    list : 'xxxx/A/list',
    query: 'xxxx/A/query',
    edit: 'xxxx/A/edit',
    ...
}

 const apiMapB = {
    list : 'xxxx/B/list',
    query: 'xxxx/B/query',
    edit: 'xxxx/B/edit',
    ...
}

Type ApiMapType = typeof apiMapA | typeof apiMapB

const context = useContext<ApiMapType|null>(null)

const APIMapProvider:FC<{value:ApiMapType}> = ({value,...props})=>{

    return <Context.Provider value={value}>
        {props.children}
    </Context.Provider>
}

const useContextAPIMap = ()=>{
    const context = useContext()
        
     
     if(!context){
         return message.error('useContextAPIMap 必须包裹在 APIMapProvider下')
     }
   
   return context
}
javascript 复制代码
const B = ()=>{
    
   return <APIMapProvider value={apiMapB}>
       <A/>
   </APIMapProvider>
}
javascript 复制代码
 const A = ()=>{
 
     return <ContextProvider value={apiMapA}>
        <SubApp/>
    </ContextProvider>
 }

叶子组件中调用接口

javascript 复制代码
const SubApp = ()=>{
   const apiMap = useContextAPIMap()
   
   const handleQuery =()=>{
       ....
       const http.get(apiMap.query)
   
   }

    return <>
       {....}
       <Button onClick={handleQuery}>查询</Button>
   </>
}

优点:

  • 优点1: 文件夹隔离组件范围,删除比较方便,删除B组件文件夹,不会影响A组件内容;
  • 优点2: 每套api对象定义链路没有动态路径,后面IDE追踪引用api地方,且api调用不会出错;

缺点:

  • 缺点1:叶子组件的每处api调用的地方都需要修改成取出useContextAPI去调用,改动量大,比较麻烦;
  • 缺点2:后须删除新增逻辑,想要复原原来A组件的直接调用api方式比较麻烦;

方案二:http使用拦截器

代码示例

由于两套接口的具有特殊规律,所以可以用拦截器去替换请求,需要替换时候正则必须要严格,需要特别小心:

比如:https://www.jsfund.cn/A/query 替换:https://www.jsfund.cn/B/query 这里替换思路:应该是路径开头是/A/的请求;不能简单写错包含A替换成B就行;

另外,由于拦截器是全局的作用范围,所以需要在离开页面的时候去卸载掉拦截器。

最后,内部的新旧文案的判断,可以使用useRouteMatch 或者useSWR做swr缓存去区分。

javascript 复制代码
const B = ()=>{
    // 入口处写入区分页面模块缓存
    useModuleType('B')
    
    useEffect(()=>{
        const id = axios.interceptors.request.use((response)=>{
            
            return response.url.replace(/(https:\/\/\w+)\/A\// ,'$1/B/')
        })
        
        return ()=>{
            axios.interceptors.request.eject(id)
        }
    
    },[])
    
    return <>
            <SubApp/>
        </>
}

自定义指定fetcher函数获取缓存结果,由于是手动写入缓存值,不需要开启验证功能;

javascript 复制代码
    const useModuleType = (moduleType: 'A' | 'B') =>{
        
        // swr key随便指定唯一就行,
       const {data} =  useSWR('_pageB_ModuleType',{
            fetcher: ()=>Promise.resolve(moduleType)
            autorun:false,
            refreshInterval: false,
            revalidateOnFocus: false,
            revalidateIfStale: false
        })
        
        return data
    }

优点:

  • 优点1:对比方法一,修改量极小,不用修改每处api调用的地方;
  • 优点2:后面恢复A模块非常方便,删除代码比较少;

缺点:

  • 缺点1:依赖替换api接口之间有比较明显的逻辑规律;
  • 缺点2:容易错误过滤替换别的模块接口,需要严格限制api接口替换规则;

📝 总结

最终我还是使用方案二,因为这次需要接口替换规则明显,用拦截器非常方便。如果接口替换规则无任何规则的话可能就比较麻烦了。抛砖引玉,如果大家有更好的方案欢迎留言评论😊。

相关推荐
用户8168694747258 小时前
深入 useMemo 与 useCallback 的底层实现
前端·react.js
AAA简单玩转程序设计8 小时前
救命!Java 进阶居然还在考这些“小儿科”?
java·前端
MediaTea8 小时前
思考与练习(第十章 文件与数据格式化)
java·linux·服务器·前端·javascript
JarvanMo8 小时前
别用英语和你的大语言模型说话
前端
江公望8 小时前
Vue3的 nextTick API 5分钟讲清楚
前端·javascript·vue.js
weixin_446260858 小时前
深入了解 MDN Web Docs:打造更好的互联网
前端
Codebee8 小时前
# 🔥A2UI封神!元数据驱动的AI交互新范式,技术人必看
前端·架构
JarvanMo8 小时前
展望 2030 年:移动开发者的未来将如何?
前端
我的xiaodoujiao8 小时前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 34--基础知识 9--文件上传功能
前端·python·测试工具·ui·pytest
辛-夷8 小时前
pinia与Vuex高频面试题
前端·vue.js