Vuex 模块中的 Websocket:尝试使用 Vuex rootstate 时出现异步问题

Websocket within Vuex module: Async issue when trying to use Vuex rootstate

我正在尝试以尽可能模块化的方式使用来自 websocket 的数据填充我的应用程序,尝试使用最佳实践等。这很难,因为即使我已经非常深入地寻求有关使用 websockets 的建议/ Vuex 和 Vue 我仍然找不到完成这项工作的模式。来回之后,我决定使用商店来管理 websocket 的状态,然后使用该 vuex 模块填充其他组件的状态,基本上是一个聊天队列和一个聊天小部件,因此需要实时使用 websockets通讯.

这是 websocket 商店。如您所见,我正在将 processWebsocket 函数转换为承诺,以便在其他模块存储操作中使用 async/await。我看到这个工作的方式(我可能错了,所以请随时纠正我)是所有将使用 websocket 模块状态的组件将等到状态准备好然后使用它(这是目前不工作):

export const namespaced = true
export const state = {
    connected: false,
    error: null,
    connectionId: '',
    statusCode: '',
    incomingChatInfo: [],
    remoteMessage: [],
    messageType: '',
    ws: null,
}
export const actions = {
    processWebsocket({ commit }) {
        return new Promise((resolve) => {
            const v = this
            this.ws = new WebSocket('xyz')
            this.ws.onopen = function (event) {
                commit('SET_CONNECTION', event.type)
                v.ws.send('message')
            }
            this.ws.onmessage = function (event) {
                commit('SET_REMOTE_DATA', event)
                resolve(event)
            }
            this.ws.onerror = function (event) {
                console.log('webSocket: on error: ', event)
            }
            this.ws.onclose = function (event) {
                console.log('webSocket: on close: ', event)
                commit('SET_CONNECTION')
                ws = null
                setTimeout(startWebsocket, 5000)
            }
        })
    },
}
export const mutations = {
    SET_REMOTE_DATA(state, remoteData) {
        const wsData = JSON.parse(remoteData.data)
        if (wsData.connectionId && wsData.connectionId !== state.connectionId) {
            state.connectionId = wsData.connectionId
            console.log(`Retrieving Connection ID ${state.connectionId}`)
        } else {
            state.messageType = wsData.type
            state.incomingChatInfo = wsData.documents
        }
    },
    SET_CONNECTION(state, message) {
        if (message == 'open') {
            state.connected = true
        } else state.connected = false
    },
    SET_ERROR(state, error) {
        state.error = error
    },
}

当我调试应用程序时,websocket 商店一切正常,我可以看到它的状态,来自服务器的数据在那里等等。当我尝试使用 websocket 填充其他组件属性时,问题就来了。当其他组件需要 websocket 状态时,这还没有准备好,所以我收到错误。这是我的一个组件尝试使用 websocket 状态的示例,我基本上从创建的循环方法中调用一个操作:

<template>
    <ul class="overflow-y-auto overflow-hidden pr-2">
        <BaseChat
            v-for="(chat, index) in sortingIncomingChats"
            :key="index"
            :chat="chat"
            :class="{ 'mt-0': index === 0, 'mt-4': index > 0 }"
        />
    </ul>
</template>

<script>
import { mapState } from 'vuex'
import BaseChat from '@/components/BaseChat.vue'
export default {
    components: {
        BaseChat,
    },
    created() {
        this.$store.dispatch('chatQueue/fetchChats')
    },
    data() {
        return {
            currentSort: 'timeInQueue',
            currentSortDir: 'desc',
            chats: [],
        }
    },
    computed: {
        sortingIncomingChats() {
            return this.incomingChats.slice().sort((a, b) => {
                let modifier = 1
                if (this.currentSortDir === 'desc') modifier = -1
                if (a[this.currentSort] < b[this.currentSort])
                    return -1 * modifier
                if (a[this.currentSort] > b[this.currentSort])
                    return 1 * modifier
                return 0
            })
        },
    },
}
</script>

这是具有 fetchChats 操作的 chatQueue Vuex 模块,用于将数据从 websocket 填充到 APP:

export const namespaced = true
export const state = () => ({
    incomingChats: [],
    error: '',
})
export const actions = {
    fetchChats({ commit, rootState }) {
        const data = rootState.websocket.incomingChats
        commit('SET_CHATS', data)
    },
}
export const mutations = {
    SET_CHATS(state, data) {
        state.incomingChats = data
    },
    SET_ERROR(state, error) {
        state.incomingChats = error
        console.log(error)
    },
}

这是我出错的地方,因为“rootState.websocket.incomingChats”在被 fetchChats 模块操作调用时还不存在,所以我得到:

TypeError: Cannot read properties of undefined (reading 'slice')

我试图将该操作转换为异步/等待操作,但它也不起作用,但正如我提到的,我对 async/await 真的很陌生,所以也许我在这里做错了:

async fetchChats({ commit, rootState }) {
    const data = await rootState.websocket.incomingChats
    commit('SET_CHATS', data)
},

任何帮助将不胜感激。

万一有人遇到同样的问题,我最后做的是在我的 websocket 模块中添加一个 getter:

export const getters = {
    incomingChats: (state) => {
        return state.incomingChatInfo
    },
}

然后在我需要用 websocket 组件填充的组件的计算值中使用 getter。

computed: {
    ...mapGetters('websocket', ['incomingChats']),
},

我在组件内的常规 v-for 循环中使用 getter:

<BaseChat
    v-for="(chat, index) in incomingChats"
    :key="index"
    :chat="chat"
    :class="{ 'mt-0': index === 0, 'mt-4': index > 0 }"
/>

这样我就不会遇到任何类型的 websocket 同步问题,因为我确信 getter 会在组件尝试使用它之前将数据传送到组件。