Search code examples
javascriptvue.jssocketsvuex

Why vuex4.0 not work as hooks inside Vue3 onMounted async function


bar1(), bar2(), bar3() are three separated situation, I would like to choose one of them as the real bar() when foo() completed, then sent to web socket, and then stored callback value by vuex.

1.bar1(): I found if I put any bar1() into onMounted scope, it couldn't work, store turn to be undefined.

2.bar2(): I pass argument "store" in XXX.vue into bar2(), and it works.

3.bar3(): Strangely, it could work if bar3() not in onMounted scope, although this is not async function, without waiting for foo(), not the way I expect.

msg_state store something in store.state..., and I would like to commit it to update its value

Questions:

  1. What's the difference between bar1(), bar2(), bar3()
  2. Why bar2() as bar() could work but bar1() as bar() could not work?
  3. It's because bar3() is inside setup() scope rather than onMounted() scope?
// In socket.js
// not work
import { useStore } from 'vuex'
export const bar1 = async(input) =>  {
// store is undefined
const store = useStore()
socket = io(url)
    socket.on('message', (msg)  = {
        // commit is not defined
        store.commit("msg_state", msg) 
    })
}

// work
export const bar2 = async(input, store) =>  {
    socket = io(url)
    socket.on('message', (msg)  = {
        store.commit("msg_state", msg) 
    })
}

// work but not async
import { useStore } from 'vuex'
export const bar3 = (input) =>  {
const store = useStore()
    socket = io(url)
    socket.on('message', (msg)  = {
        store.commit("msg_state", msg) 
    })
}

//In XXX.vue
import bar from '@/util/socket.js'
...
export default {
    setup() {
        const xxx = reactive({input: oldVal})
        const store = useStore()
        onMounted(async () => {
        //{input: oldVal}
        await foo()
        //{input: newVal}

        // option1: bar1 as bar
        await bar1(xxx.input) // counldn't work

        // option2: bar2 as bar
        await bar2(xxx.input, store) // this could work

        })
        // option3: bar3 as bar
        bar3(xxx.input) // this could work but not async
    }
}


Solution

  • bar1 and bar3 are also wrong because hooks are generally supposed to be called in setup. bar2 doesn't need access to the whole store.

    Making functions async is semantic mistake because they are asynchronous but don't involve promises. Moreover, there is message subscription and it cannot be translated to promises, unless it's one-time event.

    In case it's one-time, that commit is used outside an action means that store-specific business logic scatters over the application. The whole bar could be Vuex action:

    const bar = async ({ commit,  state }, input ) =>  {
      // socket is likely a part of state
      await new Promise(resolve => {
        socket.once('message', (msg) => {
          commit("msg_state", msg) 
          resolve(msg);
        });
      })
    }