Home > Software design >  async await in mounted lifecycle hook
async await in mounted lifecycle hook

Time:04-22

I want my component to wait until the promise is resolve in the mounted lifecycle hook but it keeps showing "undefined" (because the data is not there when the component is rendered).

<template>
    <div >
        <div >
            <TheHeader />
            <div >
                <section id="incoming-chats" >
                    <BaseButton buttonType="btnPrimary" 
                        >Serve Request</BaseButton
                    >
                    <TheChatQueue  />
                </section>
                <section id="content"  v-if="dataReady">
                    <BaseTabsWrapper>
                        <BaseTab
                            v-for="chatSession in incomingChatSessions"
                            :key="chatSession.id"
                            :title="chatSession.endUser.name"
                        >
                            <p>{{ chatSession }}</p>
                        </BaseTab>
                    </BaseTabsWrapper>
                </section>
                <!-- <section id="content" >
                    Please take a chat
                </section> -->
            </div>
        </div>
    </div>
</template>

<script>
import { mapActions, mapGetters } from 'vuex'
import BaseButton from '@/components/BaseButton.vue'
import BaseClientHeader from '../components/BaseClientHeader.vue'
import BaseTabsWrapper from '@/components/BaseTabsWrapper.vue'
import BaseTab from '@/components/BaseTab.vue'
import BaseTicketEditor from '@/components/BaseTicketEditor.vue'
import BaseTicketHistorical from '@/components/BaseTicketHistorical.vue'
import TheChatQueue from '@/components/TheChatQueue.vue'
import TheHeader from '@/components/TheHeader.vue'
import TheChatArea from '@/components/TheChatArea.vue'
export default {
    components: {
        BaseButton,
        // BaseClientHeader,
        BaseTabsWrapper,
        BaseTab,
        // BaseTicketEditor,
        // BaseTicketHistorical,
        // TheChatArea,
        TheChatQueue,
        TheHeader,
    },
    data() {
        return {
            dataReady: false,
        }
    },
    async mounted() {
        try {
            await this.callWebsocket()
            this.dataReady = true
        } catch {
            console.log('error')
        }
    },
    computed: {
        ...mapGetters({
            incomingChatSessions: 'chatSession/getIncomingChatSessions',
        }),
    },
    methods: {
        ...mapActions({
            callWebsocket: 'websocket/processWebsocket',
        }),
    },
}
</script>

As you can see in order to create a dynamic tab menu I'm looping within a computing value coming from a vuex module that process a websocket. The main problem here is that even when I have a flag in the main component (dataReady) the component is empty when rendered.

Here's the websocket module that includes the processwebsocket action. The important part for all of this is inside the "case 'chat-updated':" part of the code:

export const namespaced = true
export const state = {
    connected: false,
    error: null,
    connectionId: '',
    incomingChats: [],
    socket: {},
}
export const actions = {
    async processWebsocket({ dispatch, rootState, commit }) {
        const socket = await new WebSocket('wss://xyz')
        socket.onopen = function (event) {
            console.log('Websocket connected.')
            commit('SET_CONNECTION', event.type)
            dispatch(
                'sendMessage',
                JSON.stringify({ message: 'Hello, server.' })
            )
        }
        socket.onmessage = function (event) {
            const socketData = JSON.parse(event.data)
            const socketDataType = socketData.type
            if (
                socketData.connectionId &&
                socketData.connectionId !== state.connectionId
            ) {
                commit('SET_CONNECTION_ID', socketData.connectionId)
                dispatch(
                    'shifts/updateEventsSubscription',
                    rootState.token.agentId,
                    {
                        root: true,
                    }
                )
            } else {
                switch (socketDataType) {
                    case 'incoming-chats-updated':
                        commit('SET_INCOMING_CHATS', socketData.incomingChats)
                        break
                    case 'chat-updated':
                        console.log(socketData)
                        const chatSession = socketData.chat
                        const chatEvents = chatSession.events
                        const chatState = chatEvents.length - 1
                        if (
                            chatEvents[chatState].type === 'ChatAgentAssigned'
                        ) {
                            dispatch(
                                'chatSession/fetchChatSession',
                                chatSession,
                                {
                                    root: true,
                                }
                            )
                        } else {
                            console.log(
                                `Other Event ${chatEvents[chatState].type}`
                            )
                        }
                        break
                }
            }
        }
        socket.onerror = function (event) {
            console.log('webSocket: on error: ', event)
        }
        socket.onclose = function (event) {
            console.log('webSocket: on close: ', event)
            commit('SET_CONNECTION')
            state.socket = null
            setTimeout(startWebsocket, 5000)
        }
        commit('SET_SOCKET', socket)
    },
    async waitForOpenConnection() {
        return new Promise((resolve, reject) => {
            const maxNumberOfAttempts = 10
            const intervalTime = 200
            let currentAttempt = 0
            const interval = setInterval(() => {
                if (currentAttempt > maxNumberOfAttempts - 1) {
                    clearInterval(interval)
                    reject(new Error('Maximum number of attempts exceeded.'))
                } else if (state.socket.readyState === state.socket.OPEN) {
                    clearInterval(interval)
                    resolve()
                }
                currentAttempt  
            }, intervalTime)
        })
    },
    async sendMessage({ dispatch }, message) {
        if (state.socket.readyState !== state.socket.OPEN) {
            try {
                await dispatch('waitForOpenConnection', state.socket)
                state.socket.send(message)
            } catch (err) {
                console.error(err)
            }
        } else {
            state.socket.send(message)
        }
    },
}
export const mutations = {
    SET_CONNECTION(state, message) {
        if (message == 'open') {
            state.connected = true
        } else state.connected = false
    },
    SET_CONNECTION_ID(state, connectionId) {
        state.connectionId = connectionId
    },
    SET_SOCKET(state, socket) {
        state.socket = socket
    },
    SET_INCOMING_CHATS(state, incomingChats) {
        state.incomingChats = incomingChats
    },
    SET_ERROR(state, error) {
        state.error = error
    },
}
export const getters = {
    getIncomingChats: (state) => {
        return state.incomingChats
    },
    getConnectionId: (state) => {
        return state.connectionId
    },
}

And here's the chatSession module that I use to populate the tab menu:

export const namespaced = true
export const state = () => ({
    chatSessions: [],
})
export const actions = {
    addChatSession({ commit }, chatSession) {
        commit('ADD_CHAT_SESSION', chatSession)
    },
    fetchChatSession({ commit }, chatSession) {
        commit('SET_CHAT_SESSION', chatSession)
    },
    clearChatSessions({ commit }) {
        commit('CLEAR_CHAT_SESSIONS')
    },
}
export const mutations = {
    ADD_CHAT_SESSION(state, chatSession) {
        state.chatSessions.push({
            ...chatSession,
        })
    },
    SET_CHAT_SESSION(state, chatSession) {
        state.chatSessions.push({
            ...chatSession,
        })
    },
    CLEAR_CHAT_SESSIONS(state) {
        state.chatSessions = []
    },
}
export const getters = {
    getIncomingChatSessions: (state) => {
        return state.chatSessions
    },
}

CodePudding user response:

So it's as I said, processWebsocket action will resolved when connection to websocket will be established const socket = await new WebSocket('wss://xyz') At this moment getter getIncomingChatSessions will return an empty array (default value). Data in getIncomingChatSessions will be available only when socket.onmessage event will fire.

async mounted() {      
 await this.callWebsocket()
 this.dataReady = true
 // this.incomingChatSessions is yet empty here but this.dataReady is true, so UI is rendering but list is empty.   
},

CodePudding user response:

check out this: replace this.dataReady = true with this.$set(this, 'dataReady', true)

  • Related