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

🔥 前言

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

🤔 问题描述

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

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

💡 解决方案

假设新增的组件是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接口替换规则;

📝 总结

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

相关推荐
葱头的故事9 小时前
vant van-uploader上传file文件;回显时使用imageId拼接路径
前端·1024程序员节
Mintopia9 小时前
🇨🇳 Next.js 在国内场景下的使用分析与实践指南
前端·后端·全栈
Mintopia9 小时前
深度伪造检测技术在 WebAIGC 场景中的应用现状
前端·javascript·aigc
BUG_Jia9 小时前
如何用 HTML 生成 PC 端软件
前端·javascript·html·桌面应用·1024程序员节
木易 士心9 小时前
CSS 样式用法大全
前端·css·1024程序员节
012925209 小时前
1.1 笔记 html 基础 初认识
前端·笔记·html
2501_9293826510 小时前
[Switch大气层]纯净版+特斯拉版 20.5.0大气层1.9.5心悦整合包 固件 工具 插件 前端等资源合集
前端·游戏·switch·1024程序员节·单机游戏
非凡ghost10 小时前
Tenorshare 4DDiG(数据恢复软件) 最新版
前端·javascript·后端
非凡ghost10 小时前
WinMute(自动锁屏静音软件) 中文绿色版
前端·javascript·后端
7ayl10 小时前
Vue3 - Reactivity的核心流程
前端·vue.js