0

есть файл Data.js, в котором собираются все нужные данные:

import Vue from 'vue'
import axios from 'axios'

export default new Vue({
  data: {
    items: []
  },
  created(){
    axios('API').then(response => (this.items = response.data));
  }
})

есть компонент, который импортирует данные (этот компонент — главная страница)

<template>
    <div>
        <div v-for="item in items" :key="item.id">
          {{ item.title }}
        </div>
    </div>
</template>

<script>
import Data from '@/components/Data.js'

export default {
  data(){
    return {
      items: [],
    }
  },
  created() {
    this.items = Data.items;
  },
}
</script>

Вопрос: почему, после того, как пришел ответ с данными по аякс запросу items в компоненте не обновляется этими данными (пустота). если перейти по роутингу на другую страницу, а потом вернуться обратно — то данные отображаются корректно. Если вместо axios написать что-то типа this.items = {...} (то есть без задержки, сразу все данные захардкодить) — то данные отображаются корректно.

xaja
  • 2,969

2 Answers2

0

Проблема в том что сreated вызывается почти одновременно у обоих. Пока запустится axios главный элемент успеет скопировать пустоту.

Возможно решить через передачу промиса в итемс this.items = axios.get().

Возможно решить через обратную связь компонента https://v2.vuejs.org/v2/guide/components-custom-events.html через event.

Можно передать в Data callback c контекстом мэйна.

Но лучше исправить архитектуру. Мне кажется наследование компонента или сервис не привязанный к компоненту тут уместны.

eri
  • 35,224
  • а куда девается "реактивность"? почему когда данные приходят — они не обновляются на странице? с архитектурой мне все нравится — есть одна точка с данными, которые загружаются ОДИН раз все. – xaja Jul 30 '19 at 08:28
  • Реактивность работает от родителя к ребенку, обратно она не работает. Чтоб не было петель. – eri Jul 30 '19 at 09:39
0

У вас есть несколько путей.

1. Vuex (Наиболее правильный).

Vuex - это хранилище состояния, созданное как раз для задач вроде вашей. Это расширение функционала Vue от команды разрабатывающей основной фраемворк. Можно считать это дополнительным модулем. Когда данные можно получить и изменить из любого компонента в приложении. Описывать как это делается я не буду, это большая статья. У Vuex отличная документация доступная на русском и английском.

2. Props (Если компонент является ребенком).

Этот подход актуален только если Вы хотете предать значение из Родителя в потомка, не видя вашего HTML я не знаю подойдет ли вам этот вариант и все же, вот небольшой пример:

Props в одном примере

В шаблоне родителя вызываем потомка передавая prop с именем propName и значением propsValue:

<child-name :propName="propsValue"></child-name>

В нашем случае вместо propsValue мы передаем items:

<child-name :items="items"></child-name>

В дочернем компаненте child-name получаем props и теперь он доступен как переменная как будто бы мы указали его в data:

<template>
    <div>
        <div v-for="item in items" :key="item.id">
          {{ item.title }}
        </div>
    </div>
</template>

<script>
export default {
    props: ['items']
}
</script>

Вы не можете изменять props внутри компонента, так как это приведет к изменению его значения в родительском компоненте и перерисовке родительского и всех (если их больше одного) дочерних компонентов.

Если Вам нежно изменить props создайте его локальную копию в компоненте:

<script>
    export default {
        props: ['items'],
        data () {
            return {
                items_: null
            }
        },
        watcher: {
            items (value) {
                this.items_ = this.items;
            }
        }
    }
</script>

3. API.js (Вынести все запросы в отдельный файл и делать их при необходимости)

Необходимо учесть что использование данного подхода в связке с Vuex является одной из лучших практик. Абстрагируя запросы, вы пишите наиболее эффективную структуру. И в случае изменения метода (например POST изменятся на PUT) вам не придется изменять все подобные запросы в проекте, а достаточно будет лишь внести микроскопические изменения в Ваш API.js файл.

Худший из вариантов, но все еще рабочий. Создать отдельный API файл где описать все запросы и делать их повторно в каждом компоненте. Если вам повезет то большая часть (GET) запросов произойдет лишь один раз по тому что браузер закеширует ответ (если это настроено на бэкенде).

Выглядеть это будет вот так:

API.js

import axios from 'axios';

export function login (data) {
    return axios.post(url, data);
}

Родительский компонент

import { login } from 'api';

export default new Vue({
  data: {
    items: []
  },
  created(){
    login({login: "login"}).then(response => (this.items = response.data));
  }
})

Дочерний компонент

<script>
import { login } from 'api';

export default {
  data(){
    return {
      items: [],
    }
  },
  created() {
    login({login: "login"}).then(response => (this.items = response.data));
  },
}
</script>