Skip to content

Загрузка данных

Иногда при активации маршрута требуется получить данные с сервера. Например, перед отображением профиля пользователя необходимо получить данные о нем с сервера. Этого можно добиться двумя различными способами:

  • Получение данных после перехода: сначала перейти к новому маршруту, а затем получить данные в хуке жизненного цикла компонента маршрута. По мере загрузки данных отображать индикатор состояния загрузки.

  • Получение данных перед переходом: Получение данных перед переходом в навигационном хуке маршрутаи и завершение навигации уже когда они будут получены.

С технической точки зрения, оба варианта являются правильными - в конечном итоге все зависит от того, какой UX (user expirience) вы хотите получить.

Получение данных после перехода

При таком подходе мы сразу же осуществляем переход и рендеринг компонента маршрута, а данные получаем в хуке created компонента. Это дает нам возможность отображать состояние загрузки, пока данные пересылаются по сети, а также по-разному обрабатывать загрузку для каждого представления.

Предположим, что у нас есть компонент Post, которому необходимо получить данные для поста на основе $route.params.id:

html
<template>
  <div class="post">
    <div v-if="loading" class="loading">Loading...</div>

    <div v-if="error" class="error">{{ error }}</div>

    <div v-if="post" class="content">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>
<template>
  <div class="post">
    <div v-if="loading" class="loading">Loading...</div>

    <div v-if="error" class="error">{{ error }}</div>

    <div v-if="post" class="content">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>
js
export default {
  data() {
    return {
      loading: false,
      post: null,
      error: null,
    }
  },
  created() {
    // следить за изменениями параметров маршрута
    // для повторной загрузки данных
    this.$watch(
      () => this.$route.params,
      () => {
        this.fetchData()
      },
      // получать данные, когда представление создано и данные
      // уже реактивно отслеживаются
      { immediate: true }
    )
  },
  methods: {
    fetchData() {
      this.error = this.post = null
      this.loading = true
      // замените `getPost` на вашу утилиту для
      // получения данных / доступа к API
      getPost(this.$route.params.id, (err, post) => {
        this.loading = false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    },
  },
}
export default {
  data() {
    return {
      loading: false,
      post: null,
      error: null,
    }
  },
  created() {
    // следить за изменениями параметров маршрута
    // для повторной загрузки данных
    this.$watch(
      () => this.$route.params,
      () => {
        this.fetchData()
      },
      // получать данные, когда представление создано и данные
      // уже реактивно отслеживаются
      { immediate: true }
    )
  },
  methods: {
    fetchData() {
      this.error = this.post = null
      this.loading = true
      // замените `getPost` на вашу утилиту для
      // получения данных / доступа к API
      getPost(this.$route.params.id, (err, post) => {
        this.loading = false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    },
  },
}

Получение данных перед переходом

При этом подходе мы запрашиваем данные до завершения перехода к новому маршруту. Получение данных выполняется в навигационном хуке beforeRouteEnter в компоненте марштура, который вызывает метод next, когда данные получены. Коллбек, передаваемый в next, будет вызван после монтирования компонента:

js
export default {
  data() {
    return {
      post: null,
      error: null,
    }
  },
  beforeRouteEnter(to, from, next) {
    getPost(to.params.id, (err, post) => {
      // `setData` - это метод, определенный ниже
      next(vm => vm.setData(err, post))
    })
  },
  // когда маршрут изменяется, а этот компонент уже отрисован,
  // логика будет несколько иной.
  async beforeRouteUpdate(to, from) {
    this.post = null
    try {
      this.post = await getPost(to.params.id)
    } catch (error) {
      this.error = error.toString()
    }
  },
  methods: {
    setData(error, post) {
      if (error) {
        this.error = error
      } else {
        this.post = post
      }
    }
  }
}
export default {
  data() {
    return {
      post: null,
      error: null,
    }
  },
  beforeRouteEnter(to, from, next) {
    getPost(to.params.id, (err, post) => {
      // `setData` - это метод, определенный ниже
      next(vm => vm.setData(err, post))
    })
  },
  // когда маршрут изменяется, а этот компонент уже отрисован,
  // логика будет несколько иной.
  async beforeRouteUpdate(to, from) {
    this.post = null
    try {
      this.post = await getPost(to.params.id)
    } catch (error) {
      this.error = error.toString()
    }
  },
  methods: {
    setData(error, post) {
      if (error) {
        this.error = error
      } else {
        this.post = post
      }
    }
  }
}

Пользователь останется на предыдущем представлении, пока данные будут загружаться на новом. Поэтому рекомендуется отображать индикатор загрузки или какой-либо другой индикатор, пока данные загружаются. Если получение данных завершается неудачей, необходимо отображать какое-либо глобальное предупреждение.

Released under the MIT License.