Как работать с асинхронным поиском данных с помощью Vuex / Vue - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть простое приложение с общим стеком:

  • Внутренний сервер (Rails)
  • Приложение внешнего интерфейса (Vue)
  • База данных (PG)

Приложение Vue извлекает данные из серверной части, используя действие библиотеки хранилища Vuex следующим образом:

// store/store.js
import Vue from 'vue';
import Vuex from 'vuex';
import * as MutationTypes from '@/store/mutation-types';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    investment: {},
  },
  mutations: {
    [MutationTypes.SET_INVESTMENT_SHOW](state, investment) {
      state.investment = investment;
    },
  },
  actions: {
    fetchInvestment({ commit }, id) {
      InvestmentsApi.get(id).then((response) => {
        commit(MutationTypes.SET_INVESTMENT_SHOW, response.data);
      });
    },
  },
  getters: {
    participation: state =>
      state.investment.included[0],
  },
});

Действие вызывается в ловушке созданного жизненного цикла моего компонентавот так:

// components/Investment.vue

import { mapActions, mapGetters } from 'vuex';
export default {
  name: 'Investment',
  computed: {
    ...mapState(['investment']),
    ...mapGetters(['participation']),
  },
  created() {
    this.fetchData(this.$route.params.id);
  },
  methods: mapActions({
    fetchData: 'fetchInvestment',
  }),
};

В коде, который я написал выше, есть проблема, я на самом деле использую вычисленное значение 'участие' в моем шаблоне так:

<BaseTitleGroup
  :subtitle="participation.attributes.name"
  title="Investissements"
/>

Иконечно, поскольку я использую участие во время визуализации компонента, я получаю эту ошибку из метода getter:

Error in render: "TypeError: Cannot read property '0' of undefined"

found in

---> <InvestmentSummary> at src/views/InvestmentSummary.vue
       <App> at src/App.vue
         <Root>

Я думаю, что есть несколько решений для решения этой проблемы, и мне интересно, какое из нихЭто лучшая практика или, если есть, лучшая.

  1. Первым решением было бы добавить атрибут v-if в мой шаблон, чтобы предотвратить рендеринг элемента во время ожидания данных
    • Con: Смещение рендеринга (элемент начинает рендеринг, когда данные есть)?
    • Con: Мне бы пришлось делать это для каждого компонента моего приложения, который имеет дело с асинхронными данными, интуитивно я бы предпочел иметь дело с этим где-то еще (может быть,store?).
  2. Рендеринг элемента и помещение поддельных данных в хранилище, например «Загрузка ...»
    • Con: Небольшой сбой, который видит пользователь при загрузкеего страница ужасна, когда текст переходит от загрузки к реальному тексту.
    • Con: Пустую версию моего магазина было бы больно писать и очень большой, когда мое приложение масштабируется
  3. Измените получатель, чтобы он возвращал исходные пустые данные, а не хранилище.
    • Con: Получатели усложняются
    • Con: Как насчет данных, которые не нуждаются в получателе (возможно, онинапрямую доступны из штата)
  4. Что-то еще?

Я ищу лучшее решение для работы с этим шаблоном, даже если он один извыше, я просто не уверен, чтокоторый был бы лучшимБольшое спасибо за чтение!Кроме того, я использую vue framework, но я думаю, что это скорее общий вопрос о современной среде javascript, обрабатывающей асинхронные данные и рендеринг.

Извините за длинный пост, вот картошка!(Упс, не на 9гаг;))

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

В Angular есть оператор Elvis (безопасная навигация), который является кратким способом обработки реактивных данных, которые в конечном итоге поступают.

Если это былоДоступный в компиляторе шаблонов Vue, ваш шаблон будет выглядеть так:

<BaseTitleGroup
  :subtitle="participation?.attributes?.name"
  title="Investissements"
/>

Тем не менее, Эван Вы говорит, что звучит как запах кода .

Ваша модель / состояние должны быть максимально предсказуемыми.

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

шаблон

"participation.attributes.name"

, что соответствует:

state.investment.included[0].attributes.name

store

state: {
  investment: {},
},

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

getters: {
  participation_name: state => {
    return 
      (state.investment.included 
       && state.investment.included.length
       && state.investment[0]
       && state.investment[0].attributes
       && state.investment[0].attributes.name)
      || null;
},

<BaseTitleGroup
  :subtitle="participation_name"
  title="Investissements"
/>

Но если вам нужна функциональность elvis, вы можете предоставить ее в виде миксина.

var myMixin = {
  computed: {
    elvis: {
      get: function() {
        return (known, unknown) => {
          // use regex split to handle both properties and array indexing
          const paths = unknown.split(/[\.(\[.+\])]+/); 
          let ref = known
          paths.forEach(path => { if (ref) ref = ref[path] });
          return ref;
        }
      }
    },
  }
}

export default {
  name: 'Investment',
  ...
  mixins: [myMixin],
  computed: {
    ...mapState(['investment']),
    participation_name() {
      return this.elvis(this.investment, 'included[0].attributes.name')
    }
  },
  ...
};
0 голосов
/ 21 сентября 2018

Я не думаю, что есть лучшее решение, просто выберите одно и используйте его везде, вместо того, чтобы смешивать их все.

v-if однако может быть лучше, если вы хотите визуализировать данные из вложенного свойства - v-if="object.some.nested.property v-for="el in object.some.nested.property" будет работать, но предопределение object = {} не будет (будет выдано сообщение об ошибке, что someundefined, и вы пытаетесь получить к нему доступ.)

Я бы не стал помещать какие-либо фальшивые данные, как в вашем примере, но вы можете использовать ES6 Classes , чтобы определить объекты по умолчанию и установить их в качествезначения по умолчанию.Это также устраняет вышеуказанную предопределенную проблему до тех пор, пока ваш объект класса имеет правильную структуру (и он также синтетически прозрачен и прост для понимания).

Что касается третьего варианта - пустые данные для получателей неЭто должно быть сложно - просто измените ваш метод получения на:

getters: {
    participation: state =>
      state.investment.included[0] || new DefaultParticipationObject() // I don't know what's in included array
  },

При этом используется state.investment.included[0], если он определен, и объект по умолчанию в противном случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...