博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

vue2 & vue-router 隐蔽的闭包问题

Posted on 2024-06-23 00:28  kpi311  阅读(22)  评论(0编辑  收藏  举报

闭包总是在不经意间出现。

1 问题发现

收到一个问题,路由切换之后再回到之前的页面,页面上有个组件每次会增加一个。

切换前 切换前
多次切换后 多次切换后

看了下代码,mounted的时候会添加这个组件。说明添加的逻辑就是触发问题的位置。

<script>
import TestComp from './components/TestComp.vue';

const showList = {
  inList: []
}
const noShowList = {
  inList: []
}

export default {
  name: 'Page1',
  components: {},
  data() {
    return {
      list: this.$route.query.show ? noShowList : showList
    }
  },
  computed: {},
  mounted() {
    this.list.inList = [TestComp, ...this.list.inList]
  },
  methods: {}
}

</script>

2 问题溯源

看修改的逻辑,是对原始的引用对象进行了修改。这里产生了一个想法:这里有闭包保存了状态,避开了Vue的新建-销毁逻辑?

由于触发是路由切换,所以直接杀到vue-router官网。果然,对于异步组件的处理是很明确的:Vue Router will only fetch it when entering the page for the first time, then use the cached version.

vue-router官网说明 vue-router官网说明

所以这份存起来的模板对象上有个闭包,是程序员自己写出来的。

3 解决方案

知道了有闭包,解决起来就简单了:将这个对象放到data函数里。这样确保每次加载组件对象的时候,都生成新的对象。

<script>
import TestComp from './components/TestComp.vue';

export default {
  name: 'Page1',
  components: {},
  data() {
    const showList = {
      inList: []
    }
    const noShowList = {
      inList: []
    }
    return {
      list: this.$route.query.show ? noShowList : showList
    }
  },
  computed: {},
  mounted() {
    this.list.inList = [TestComp, ...this.list.inList]
  },
  methods: {}
}

</script>

4 拓展思考

对于Vue3而言,这种问题好像不会存在于setup中,毕竟作为函数上下文,每次调用都是最新的。不过如果还有在用optionalAPI的人就有难了。

5 总结

实战中莫名其妙的闭包问题往往是与框架机制挂钩的,所以脱离实际环境去谈论闭包很多时候得到的都是形而上学的认识。