Перед загрузкой компонента дождитесь загрузки значения VueX - PullRequest
1 голос
/ 13 июня 2019

Когда пользователь пытается напрямую перейти к загрузке URL-адреса компонента, в моих действиях vuex выполняется http-вызов, который определит значение в моем состоянии после его разрешения.

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

Например, в моем компоненте

export default {
  computed: {
    ...mapState({
      // ** this value needs to load before component mounted() runs **
      asyncListValues: state => state.asyncListValues
    })
  },

  mounted () {
    // ** I need asyncListValues to be defined before this runs **
    this.asyncListValues.forEach((val) => { 
      // do stuff
    });
  }
}

Как заставить мой компонент ждать загрузки asyncListValues, прежде чем загружать мой компонент?

Ответы [ 3 ]

1 голос
/ 14 июня 2019

Поскольку вы упомянули vue-router в своем вопросе, вы можете использовать beforeRouteEnter, который предназначен для отсрочки рендеринга компонента.

Например, если у вас есть маршрут с именем "photo":

import Photo from "../page/Photo.vue";

new VueRouter({
  mode: "history",
  routes: [
    { name: "home", path: "/", component: Home },
    { name: "photo", path: "/photo", component: Photo }
  ]
});

Вы можете использовать beforeRouteEnter следующим образом:

<template>
  <div>
    Photo rendered here
  </div>
</template>
<script>
export default {
  beforeRouteEnter: async function(to, from, next) {
    try {
      await this.$store.dispatch("longRuningHttpCall");

      next();
    } catch(exception) {
      next(exception);
    }
  }
}
</script>

Что он делает, ждать завершения действия, обновлять свое состояние так, как вы хотите, и затем вызыватьnext() скажет маршрутизатору продолжить процесс (рендеринг компонента внутри <router-view></router-view>).

Скажите, нужен ли вам пример без ES6 (если вы не используете этот синтаксис, например).

На этой странице вы можете проверить официальную документацию по номеру beforeRouteEnter, а также узнать, что вы также можете поместить ее на уровне маршрута, используя beforeEnter.

1 голос
/ 14 июня 2019

Способ сделать это - сохранить значения состояния.

Например, если ваш магазин использует один API, вы должны сделать что-то подобное.Однако для нескольких API рекомендуется хранить каждое состояние загрузки API по отдельности или использовать отдельный объект для каждого API.

Обычно вы можете иметь 4 состояния, которые я предпочитаю иметь вглобально доступный модуль:

// enums.js
export default {
  INIT: 0,
  LOADING: 1,
  ERROR: 2,
  LOADED: 3
};

Затем переменная может храниться в состоянии vuex, где apiState инициализируется с помощью INIT.Вы также можете инициализировать массив с помощью [], но в этом нет необходимости.

import ENUM from "@/enums";
// store.js
export default new Vuex.Store({
  state: {
    apiState: ENUM.INIT,
    accounts: [],
    // ...other state
  },
  mutations: {
    updateAccounts (state, accounts) {
      state.accounts = accounts;
      state.apiState = ENUM.LOADED;
    },
    setApiState (state, apiState) {
      state.apiState = apiState;
    },
  },
  actions: {
    loadAccounts ({commit) {
      commit('setApiState', ENUM.ERROR);
      somFetchInterface()
        .then(data=>commit('updateAccounts', data))
        .catch(err=>commit('setApiState', ENUM.ERROR))
    }
  }
});

Затем, добавив несколько computed s, вы можете выбрать, какой компонент отображается.Это показывает преимущество использования состояния, поскольку вы можете легко определить состояние ошибки и показать анимацию загрузки, когда состояние не готово.

<template>
  <ChildComponent v-if="apiStateLoaded"/>
  <Loader v-if="apiStateLoading"/>
  <Error v-if="apiStateError"/>
</template>
<script>
import ENUM from "@/enums";
export default {
  computed: {
    ...mapState({
      apiState: state=> state.apiState
    }),
    apiStateLoaded() {
      return this.apiState === ENUM.LOADED;
    },
    apiStateLoading() {
      return this.apiState === ENUM.LOADING || this.apiState === ENUM.INIT;
    },
    apiStateError() {
      return this.apiState === ENUM.ERROR;
    },
  })
}
</script>

В качестве альтернативы, если вы просто инициализируете свой asyncListValues в хранилище пустым массивом [], вы можете избежать ошибок, ожидающих массив.

1 голос
/ 14 июня 2019

Один из подходов - разделить ваш компонент на два разных компонента. Ваш новый родительский компонент может обрабатывать выборку данных и рендеринг дочернего компонента, когда данные готовы.

ParentComponent.vue

<template>
  <child-component v-if="asyncListValues && asyncListValues.length" :asyncListValues="asyncListValues"/>
  <div v-else>Placeholder</div>
</template>
<script>
export default {
  computed: {
    ...mapState({
      asyncListValues: state => state.asyncListValues
    })
  }
}
</script>

ChildComponent.vue

export default {
  props: ["asyncListValues"],
  mounted () {
    this.asyncListValues.forEach((val) => { 
      // do stuff
    });
  }
}
...