programing

마운트된 수명 주기 후크의 비동기 대기

bestprogram 2023. 7. 16. 13:45

마운트된 수명 주기 후크의 비동기 대기

마운트된 라이프사이클 후크에서 약속이 해결될 때까지 구성 요소를 기다리지만 구성 요소가 렌더링될 때 데이터가 없기 때문에 "정의되지 않음"으로 계속 표시됩니다.

<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>

보시는 바와 같이 동적 탭 메뉴를 만들기 위해 웹 소켓을 처리하는 vuex 모듈에서 나오는 컴퓨팅 값 안에서 루프하고 있습니다.여기서 주요 문제는 메인 구성 요소(dataReady)에 플래그가 있더라도 렌더링 시 구성 요소가 비어 있다는 것입니다.

프로세스 웹 소켓 작업이 포함된 웹 소켓 모듈입니다.이 모든 것에 대한 중요한 부분은 코드의 "case 'chat-updated:" 부분 안에 있습니다.

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

다음은 탭 메뉴를 채우는 데 사용하는 chatSession 모듈입니다.

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

그래서 제가 말한 것처럼,processWebsocket웹 소켓에 대한 연결이 설정되면 작업이 해결됩니다.const socket = await new WebSocket('wss://xyz')이 순간에 더 좋아집니다.getIncomingChatSessions빈 배열(기본값)을 반환합니다.데이터 위치getIncomingChatSessions의 경우에만 사용할 수 있습니다.socket.onmessage이벤트가 발생합니다.

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

이것을 확인하세요.this.dataReady = true와 함께this.$set(this, 'dataReady', true)

언급URL : https://stackoverflow.com/questions/71952098/async-await-in-mounted-lifecycle-hook