Как использовать async / await в крючках жизненного цикла vue с vuex?

#vue.js #vuejs2 #vue-component #vuex

#vue.js #vuejs2 #vue-компонент #vuex

Вопрос:

Когда я отправляю действие в компоненте App.vue в перехвате жизненного цикла mounted (), оно запускается после загрузки других компонентов. Я использую async / await в своем действии и подключил крючок жизненного цикла.

Файл App.vue

 methods: {
   ...mapActions({
      setUsers: "setUsers",
   }),
},
async mounted() {
        try {
            await this.setUsers();
        } catch (error) {
            if (error) {
                console.log(error);
            }
        }
    },
 

action.js файл:

 async setUsers(context) {
        try {
            const response = await axios.get('/get-users');
 
            console.log('setting users');
 
            if (response.data.success) {
                context.commit('setUsers', {
                    data: response.data.data,
                });
            }
        } catch (error) {
            if (error) {
                throw error;
            }
        }
    },
 

В компоненте списка пользователей мне нужно получить пользователей из vuex. Итак, я использую mapGetters для получения списка пользователей.

 ...mapGetters({
            getUsers: "getUsers",
        }),
    mounted() {
            console.log(this.getUsers);
    },
 

Но проблема заключается в том, что «настройка входа пользователей» в консоль выполняется после входа в консоль this.getUsers . .

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

Как я могу запустить app.vue file перед запуском любых других компонентов?

Ответ №1:

Вы правильно используете async await в своих компонентах. Важно понимать, что async await это не задерживает выполнение вашего компонента, и ваш компонент все равно будет отображаться и проходить через различные перехваты жизненного цикла, такие как mounted .

Что async await делает, так это задерживает выполнение текущего контекста, если вы используете его внутри функции, код после await того, как обещание будет выполнено, и в вашем случае вы используете его в created перехвате жизненного цикла, что означает, что код внутри mounted перехвата жизненного цикла, который является функцией, будетрешается после ожидания.

Итак, что вы хотите сделать, это убедиться, что вы визуализируете компонент только при получении данных.

Вот как это сделать:

  1. Если компонент является дочерним компонентом родительского компонента, который вы можете использовать v-if , то при поступлении данных установите для data значение true, например:
 data() {
  return {
   hasData: false,
  }
}

async mounted() {
 const users = await fetchUsers()
 this.hasData = true;
} 
 <SomeComponent v-if="hasData" /> 

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

Простое эмпирическое правило заключается в использовании watch с переменными, которые меняются не часто, если данные, которые вы получаете, в основном доступны только для чтения, вы можете использовать данные, если нет, вы можете добавить свойство в Vuex, например loadingUsers .

Вот пример того, как это сделать:

   data: {
    return {
     hasData: false,
    }
  },
  
  computed: {
   isLoading() {
    return this.$store.state.app.users;
   }
  },
  
  watch: {
    isLoading(isLoading) {
      if (!isLoading) {
        this.hasData = true;
      }
    }
  } 
 <SomeComponent v-if="hasData" /> 

Ответ №2:

если вы извлекаете данные из API, то лучше отправить действие внутри created, где DOM еще не визуализирован, но вы все равно можете использовать «this» вместо mounted . Вот пример, если вы работаете с модулями Vuex:

 created() {
  this.fetchUsers();
},
methods: {
  async fetchUsers() {
    await this.$store.dispatch('user/setUsers');
  },
},
computed: {
  usersGetters() {
    // getters here
  },
},
 

Ответ №3:

Вопрос: Вы ожидаете await this.setUsers(); , что приложение будет запускаться каждый раз при загрузке (независимо от того, какая страница / компонент отображается)?

Если да, то у вас App.vue все в порядке. И в вашем «компоненте списка пользователей» его также можно использовать mapGetters для получения значений (обратите внимание, что оно должно быть вычислено). Проблема в том, что сначала вы должны «дождаться» завершения setUsers действия, чтобы ваш getUsers компонент мог иметь значение.

Простой способ исправить это — использовать условный рендеринг и отображать компонент только тогда, когда getUsers он определен. Возможно, вы можете добавить a v-if в свой родительский компонент «Компонента списка пользователей» и загружать его только тогда, когда v-if="getUsers" значение true. Тогда ваша смонтированная логика также будет работать нормально (поскольку данные уже есть).