Jmingzi / blog

温故而知新

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vue ssr疑问点

Jmingzi opened this issue · comments

1. 关于getMatchedComponents

entry-server中,根据当前路由匹配出的组件,只包含路由组件么?而不包含路由组件中引用的子组件。
例如:

// route Component A
// 引入了 BottomTab 组件,在BottomTab组件中需要预取数据
<route-a>
  <bottom-tab />
</route-a>

而此时组件BottomTab,并没有被getMatchedComponents匹配到。

2.关于在客户端预取数据

起初看到官方文档数据的预取与渲染这里时,对客户端数据的预取很不理解,客户端为何要预取数据?

官方有2种实现:

// 1. 在entry-client.js中实现
router.onReady(() => {
  // 在路由初始化完成后,注册钩子函数去处理路由变化时,对组件的一些操作,比如数据预取。
  router.beforeResolve((to, from, next) => {
    // 在这里会根据to, from,来getMatchedComponents
    // 从而匹配出相应的路由组件
    // 筛选出to和from不一致的情况下,也就是跳转的路由与当前不一致时,才去预取数据
    // 为什么会这么做?我猜是在这种情况下,例如获取文章详情,或分类列表
    // 它们的路由看起来是这样的:`/detail/1`,`/list/1`,当路由变化时,组件并没有改变
    // 所以不需要去预取数据的,所以也就避免了二次预取(double-fetch)已有的数据
    const matched = router.getMatchedComponents(to)
    const prevMatched = router.getMatchedComponents(from)
    let diffed = false
    const activated = matched.filter((c, i) => {
      return diffed || (diffed = (prevMatched[i] !== c))
    })
    if (!activated.length) {
      return next()
    }
  })
})

我们再来看第二种实现来论证这个观点:

// 2. 通过全局的mixin,来注册生命周期钩子函数
Vue.mixin({
 // beforeMount只会在组件初始化时调用
 // 在`/detail/1`,`/list/1`这种路由发生变化时,是不会调用的
 // 也就论证了上面的说法成立
 beforeMount () {
   const { asyncData } = this.$options
   if (asyncData) {
     // 将获取数据操作分配给 promise
     // 以便在组件中,我们可以在数据准备就绪后
     // 通过运行 `this.dataPromise.then(...)` 来执行其他任务
     this.dataPromise = asyncData({
       store: this.$store,
       route: this.$route
     })
   }
 }
})

在实际的项目中,规避double-fetch的做法有很多,客户端数据预取的实现也有很多,通常我们是在created钩子中去做这个事情,例如:

{
  created() {
    if (this.list === null) {
      // 当list为null时,才去取数据
      this.fetchData()
    }
  }
}

我想,这跟官方的数据的预取是一个道理吧