Как проверить, завершилось ли действие, вызванное из другого компонента?

Имеется SPA приложение с чатом (система диалогов с привязкой к определенной статье). В главном шаблоне MainApp вызывается действие, инициализирующее начальные данные чата (статьи пользователя и имеются ли непрочитанные сообщения к данной статье):

created() {
           this.$store.dispatch('chat/InitChatSystem');
        },

Инициализирующее действие:

InitChatSystem() {    
        axios.get('/api/initChat')
            .then(res => {
                this.commit('chat/initArticles', res.data.articles);                
                this.commit('chat/initNotifications', res.data.notifications);               
            })
            .catch(err => {
                console.log(err);                
            })
},

Мутация действия:

initArticles(state, data) {   
        for (let i = 0, len = data.length; i < len; i++) {
            state.articles.push(data[i]);
        }    
},

На странице с чатом (keep-alive) вызывается мутация:

activated() {            
            this.$store.commit('chat/openConversationArticle', this.article_id);            
        },

Мутация:

openConversationArticle(state, article_id) {
           ....
//Ищется статья, чтобы пометить все сообщения как прочитанные
            let notification_ids = [];            
            let article_index = state.articles.findIndex(x => +x.id === +article_id);
            console.log(article_index); //Всегда -1 (т.е. не найдено)
            state.articles[article_index].notification = false;
            state.articles[article_index].notification_count = 0;            
            if (notification_ids.length > 0) {
                axios.post('/api/markAsReadNotification', {notification_ids: notification_ids});
            }
        },

Если сразу открыть в браузере страницу с чатом, то появляется ошибка Cannot set property 'notification' of undefined в данной строке:

state.articles[article_index].notification = false

Т.е. в мутации openConversationArticle state.articles еще не заполнены (проверял, длина массива = 0).

Как можно перед вызовом мутации проверить завершились ли другие мутации?

Пробовал в InitChatSystem сделать

return new Promise((resolve, reject) => {
...
}

А далее вот так:

openConversationArticle({ dispatch, commit }) {
    return dispatch('InitChatSystem').then(() => {
      commit('openConversationArticle')
    })
  }

Однако в таком случае: сначала вызывается действие InitChatSystem в главном шаблоне, потом еще раз это действие dispatch('InitChatSystem') в openConversationArticle и только потом мутация статьи.
  • Вопрос задан
  • 178 просмотров
Решения вопроса 2
0xD34F
@0xD34F Куратор тега Vue.js
Да не надо ничего проверять. Что у вас является следствием завершившегося действия? - наличие нужных данных. Сделайте соответствующий геттер, и повесьте на экземпляр компонента v-if с этим геттером. Пока данных нет - экземпляр компонента не будет рендериться, а значит и мутация, требующая отсутствующих данных, тоже вызвана не будет, а значит и ошибки не будет.
Ответ написан
Комментировать
bingo347
@bingo347
Crazy on performance...
Во-первых, dispatch возвращает промис, притом если экшен возвращает промис, то dispatch вернет именно его
То есть можем сделать примерно следующее:
// экшн:
InitChatSystem() {    
        return axios.get('/api/initChat')
            .then(res => {
                this.commit('chat/initArticles', res.data.articles);                
                this.commit('chat/initNotifications', res.data.notifications);               
            })
            .catch(err => {
                console.log(err);                
            })
},


// хук:
created() {
  this.$store.dispatch('chat/InitChatSystem').then(() => {
    // тут запускаем нашу мутацию
    // но как я понял, она в дочернем компоненте
    // нужно навесить ref на компонент, а в самом компоненте сделать метод запуска
    // а здесь будет что-то типа:
    this.$refs.child.run();
  });
},


Второй вариант, чисто на возможностях Vuex:
// дождемся, когда в state.articles появятся данные
activated() {            
  const unwatch = this.$store.watch(state => state.articles.length, length => {
    if(length === 0) { return; }
    unwatch();
    this.$store.commit('chat/openConversationArticle', this.article_id);
  });
},
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
prochorz
@prochorz
Vue.js, NuxtJs, Wordpress
Из компонента пинайте Action , который делает запрос на Бек. Action - промис, в случае успеха делает мутациию в случае если нет возвращение false. А в компоненте получаете результат Action . И обрабатывает then/catch
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы