前端同一个接口同时被调用两次的原因

一、问题

1.最近写代码遇到了两次这种同一个接口几乎同时被调用两次情况,决定记录一下。

二、场景及解决方法

1.场景一

父组件Parent给子组件Son传参props1,子组件Son只在初始化时能够正确接收到 子组件传过来的值props1,之后父组件中的props1的值变化,子组件中接收的props1是会进行响应式更改的。

1)但是我的需求是: 在子组件中知道props1变化,就需要 调用函数,进行相应的处理。 

我怎么知道 props1什么时候变化了呢?-----watch监听 props1的变化,监听到变化时,做我想做的事情,比如调用函数functionA(里面调用了接口 searchPatient)!!!!!!

2)问题来了:我写好了之后,进入这个页面,发现functionA有时候被调用了两次(接口 searchPatient被调用了两次),并且 props作为接口传参,前后两次调用接口的传参不同,导致两次取到的数据不同。因为 两次调用接口,接口的响应时间不同,异步了,最终导致有时取到的数据是正确的,有时取到的数据是错误的!

3)产生问题的原因: 想了很久都觉得自己没有问题,父组件传过来值,我在子组件中也只接收了一次并且没有修改过 props1的值,怎么就有两次变化?况且其他页面也有类似的操作,也没有调用两次接口呀!!!

最后发现:竟然是因为我在父组件中 给props1赋了两次值。一次是在声明props1变量时赋值为false,一次是在mounted中 因为localStorage中可能存了值,我想判断一下后再给props1赋值

localStorage中存的是 false的时候,确实只能监听到props1变化了一次;接口只调用一次---没有问题;

localStorage中存的是true的时候,props1从false变成了true,子组件监听懂啊 props1变化了两次,所以接口被调用了两次---有问题。

错误代码如下:

    export default {
        data() {
            return {
                // 是否查看所有
                searchAll: this.initSearchAll(),
            }
        },
        mounted() {
            if (sessionStorage.getItem('isSearchAllPatient')) {
                return JSON.parse(sessionStorage.getItem('isSearchAllPatient'));
            } else {
                sessionStorage.setItem('isSearchAllPatient', false);
                return false;
            }
        }
    }

注:如果不是仔细分析,我也以为没有影响的!!!这也间接证明 子组件和父组件 几乎是同步加载的。

       上述props1是泛指,具体为下面代码中的 searchAll

4)解决方法:

a.方法一:推荐

   在初始化变量 searchAll的时候直接调用一个方法赋值就可以了,不要在mounted中再赋值了!!!

   正确代码如下:

    export default {
        data() {
            return {
                // 是否查看所有
                searchAll: this.initSearchAll(),
            }
        },
        mothods: {
            // 初始化仅看我的和查看全部
            initSearchAll() {
                if (sessionStorage.getItem('isSearchAllPatient')) {
                    return JSON.parse(sessionStorage.getItem('isSearchAllPatient'));
                } else {
                    sessionStorage.setItem('isSearchAllPatient', false);
                    return false;
                }
            },
        }
    }

b.方法二: 

   在子组件上加上  v-if=“isShowSon",isShowSon初始化为false等待我在mounted给变量 SearchAll赋值完成后,再加载 子组件Son(isShowSon赋值为true).

    不推荐,因为使用了多余的变量,且赋值两次。一次赋值就可以解决的问题,不建议 画蛇添足。

2.场景二

一个页面有很多患者,当我选择了一个患者后,进入改患者对应的页面,存储了改患者的信息currentOperaMsg;当我回到有很多患者的其他页面,我希望不再存储刚才那个患者的信息。想到可以根据路由来判断我到底要在什么时候置空患者的信息。这一切都看上去很合理,没有问题。

1)但是有一个新的需求是:在单个患者对应的页面,可以切换到其他患者,我必须监听currentOperaMsg的变化才能够重新调 页面中的接口;

2)还有另外一个问题:一个患者也对应很多页面我在每个页面都写一个监听到患者变化,然后调用改页面的接口很不合理。----为了简化,想到监听到患者变化时,直接刷新页面,这样只需要在患者所在的每个页面调用一个公共函数reload就可以 实现:切换患者时,改患者对应的所有页面都可以刷新。

3)问题来了:上面的看起来都挺合理的,但是却发现当你从 某个患者所在的页面切换到所有患者的页面时,所有患者的页面接口都被调用了两次。

4)问题产生的原因路由变化早于组件的销毁,当路由变化时:所有患者的页面被加载一次,同时判断到切换到所有患者的页面,currentOperaMsg被 置为{};单个患者所在的页面还没有被销毁,监听到 currentOperaMsg的变化,执行reload函数,又加载了一次页面。

前端同一个接口同时被调用两次的原因_第1张图片

 

 5)解决方法

   真的有这种需求时,可以在除了单个患者及全部患者以外的路由将 currentOperaMsg置为{},因为全部患者页面带有 currentOperaMsg相关的信息应该是不影响业务的。

 6)根本的解决方法

   上述的需求其实是不合理的,我在除了单个患者的页面拥有 currentOperaMsg理论上不会影响其他页面的。而且对于导航式编程而言,点击浏览器的返回按钮后应该正常 显示之前的页面。如果真的把currentOperaMsg设置为{},在上述场景下,点击 浏览器左上角的 返回按钮后,单个患者页面就没有患者信息了,需要传单个患者信息的接口很可能会报错,如下图所示。这显然是不合理的。

 三、总结

1.上述两种情况都和 监听变量有关系。但直接原因不同。

2.同一个接口调用两次可能原因: 

   a.给一个变量赋值了 两次监听到两次变化后执行了两次接口;

   b.路由变化和手动刷新页面同时进行导致页面被加载两次,接口被调用两次。

3.写代码注意事项

   a.尽可能减少没必要的赋值,保持代码的简洁性。不要随便给变量赋值,赋值的时候要注意初始值的数据类型是否正确。

   b.有监听的地方,要仔细考虑一下,是否会影响其他地方。

4.以上是目前遇到的场景,将持续更新!

/*

希望对你有帮助!

如有错误,欢迎指正,非常感谢!

*/

你可能感兴趣的:(前端,笔记,前端)