fetch.client.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import Vue from 'vue'
  2. import { hasFetch, normalizeError, addLifecycleHook, createGetCounter } from '../utils'
  3. const isSsrHydration = (vm) => vm.$vnode && vm.$vnode.elm && vm.$vnode.elm.dataset && vm.$vnode.elm.dataset.fetchKey
  4. const nuxtState = window.__NUXT__
  5. export default {
  6. beforeCreate () {
  7. if (!hasFetch(this)) {
  8. return
  9. }
  10. this._fetchDelay = typeof this.$options.fetchDelay === 'number' ? this.$options.fetchDelay : 200
  11. Vue.util.defineReactive(this, '$fetchState', {
  12. pending: false,
  13. error: null,
  14. timestamp: Date.now()
  15. })
  16. this.$fetch = $fetch.bind(this)
  17. addLifecycleHook(this, 'created', created)
  18. addLifecycleHook(this, 'beforeMount', beforeMount)
  19. }
  20. }
  21. function beforeMount() {
  22. if (!this._hydrated) {
  23. return this.$fetch()
  24. }
  25. }
  26. function created() {
  27. if (!isSsrHydration(this)) {
  28. return
  29. }
  30. // Hydrate component
  31. this._hydrated = true
  32. this._fetchKey = this.$vnode.elm.dataset.fetchKey
  33. const data = nuxtState.fetch[this._fetchKey]
  34. // If fetch error
  35. if (data && data._error) {
  36. this.$fetchState.error = data._error
  37. return
  38. }
  39. // Merge data
  40. for (const key in data) {
  41. Vue.set(this.$data, key, data[key])
  42. }
  43. }
  44. function $fetch() {
  45. if (!this._fetchPromise) {
  46. this._fetchPromise = $_fetch.call(this)
  47. .then(() => { delete this._fetchPromise })
  48. }
  49. return this._fetchPromise
  50. }
  51. async function $_fetch() {
  52. this.$nuxt.nbFetching++
  53. this.$fetchState.pending = true
  54. this.$fetchState.error = null
  55. this._hydrated = false
  56. let error = null
  57. const startTime = Date.now()
  58. try {
  59. await this.$options.fetch.call(this)
  60. } catch (err) {
  61. if (process.dev) {
  62. console.error('Error in fetch():', err)
  63. }
  64. error = normalizeError(err)
  65. }
  66. const delayLeft = this._fetchDelay - (Date.now() - startTime)
  67. if (delayLeft > 0) {
  68. await new Promise(resolve => setTimeout(resolve, delayLeft))
  69. }
  70. this.$fetchState.error = error
  71. this.$fetchState.pending = false
  72. this.$fetchState.timestamp = Date.now()
  73. this.$nextTick(() => this.$nuxt.nbFetching--)
  74. }