简体   繁体   中英

async await in mounted lifecycle hook

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 class="min-w-[800px] w-full h-screen overflow-hidden">
        <div class="flex flex-col">
            <TheHeader />
            <div class="flex mt-4 h-[830px] overflow-hidden">
                <section id="incoming-chats" class="min-w-[344px] px-2">
                    <BaseButton buttonType="btnPrimary" class="w-full mb-4"
                        >Serve Request</BaseButton
                    >
                    <TheChatQueue class="max-h-screen overflow-y-scroll pb-4" />
                </section>
                <section id="content" class="w-full mx-2 pr-2" 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" class="w-full mx-2 pr-2">
                    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
    },
}

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.   
},

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM