Home » vue » Websockets in Vue/Vuex (how to receive emissions from server)

Websockets in Vue/Vuex (how to receive emissions from server)

Posted by: admin November 26, 2021 Leave a comment

Questions:

So until now I just socket.io-client to do communication to a WebSocket in my Vue component.
Now I am adding Vuex to the project and declared a Websocket like this

Vue.use(new VueSocketIO({
  debug: true,
  connection: 'http://192.168.0.38:5000',
}));

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount('#app');

1) Should i have stuff like emitting some messages in the component themselves now or in the store?

2) Before I introduced the changes I could do something like this:

socket.on('connect', function () {
      console.error('connected to webSocket');
      socket.emit('my event', { data: 'I\'m connected!' });
    });

socket.on('my response', function(data){
      console.log('got response');
      console.log(data.data);
    });

When sending the “my event”, the flask server would respond with “my response”. Now I am trying the same thing from a component after the changes like this.

    this.$socket.emit('my_event', { data: 'I\'m connected!' });
    console.error('send to websocket ');

    this.$options.sockets.my_event = (data) => {
      console.error('received answer ');
      console.error(data);
    };

The my_event reaches my flask server however I don’t get the response receiving to work. What am I doing wrong?
Also because I was asking about whether I should put this in the component or the store, I found stuff like this for the store:

SOCKET_MESSAGECHANNEL(state, message) {
      state.socketMessage = message
    }

The explanation was “So, for example, if your channel is called messageChannel, the corresponding Vuex mutation would be SOCKET_MESSAGECHANNEL” and it is from this site https://alligator.io/vuejs/vue-socketio/.

I think I don’t really get what a channel is at this point. Is the my_response I emit from the flask server also a channel?
Thanks for your help in advance!

EDIT: So now I am trying to listen and emit to a websocket from my store. For this I tried the following: In main.js I have this part:

Vue.use(new VueSocketIO({
  debug: true,
  connection: SocketIO('http://192.168.0.38:5000'),
  vuex: {
    store,
    actionPrefix: 'SOCKET_',
    mutationPrefix: 'SOCKET_',
  },
}));

Then in my store.js I have the following:

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    count: 0,
    title: 'title from vuex store',
    isConnected: false,
  },
  mutations: {
    increment(state) {
      state.count += 1;
    },
    emitSth(state) {
      this.sockets.emit('my_event', { data: 'I\'m connected!' });
      console.log(state.count);
    },
    SOCKET_my_response(state) {
      state.isConnected = true;
      alert(state.isConnected);
    },
    SOCKET_connect(state) {
      state.isConnected = true;
      alert(state.isConnected);
    },
  },
});

And in my component I have this script:

export default {
  name: 'ControlCenter',
  data() {
    return {
      devices: [{ ip: 'yet unknown' }], // placeholder so line 12 does not throw error before actual device info fetched
      thisDeviceIndex: 0,
      currentLayoutIndex: 0,
      layouts: [],
    };
  },
  computed: mapState([
    'title',
    'count',
  ]),
  components: {
    DNDAssign,
    FirstPage,
  },
  methods: {
    // mapMutation helper let's us use mutation from store via this instead of this.$store
    ...mapMutations([
      'increment',
      'emitSth',
    ]),
    incrementMutation() {
      this.increment();
    },
    emitEvent() {
      this.emitSth();
    },
    // some other stuff here
  },
  created() {
    // inital fetching of layouts
    console.log('fetching layouts from backend');
    this.getAllLayouts();

    console.log(this.$socket);
  },
};

I also have a button for the triggering of the emit which is

<b-button
type="button"
variant="success"
v-on:click="emitEvent()"
>
emit event
</b-button>

The connected in the store gets triggered, however I get the following errors for the emitting:

  • “TypeError: Cannot read property ’emit’ of undefined”
  • “Cannot read property ’emit’ of undefined”

Also I am not sure about the naming in the mutations. If I have this mutationPrefix, shouldn’t it be enough to just use connect instead of SOCKET_connect?

Answers:

First of all, if you are using Vue-Socket.io version 3.0.5>, uninstall it and install version 3.0.5

npm uninstall vue-socket.io
npm install [email protected]

then lock the version in packege.json: "vue-socket.io": "3.0.5", latest update seems to breaks the library, read more here

Now to receive events from socket.io server, you can do:

this.sockets.subscribe("my response", (data) => {
    console.log(data);
});

or if want put listener on component level, you need to add sockets object on the component export, for example:

export default {
    ...
    sockets: {
        "my response": function (data) {
            console.log(data);
        }
    }
    ...
}

Since you are not using Vuex Integration on the VueSocketIO, you dont need to put additional function in store mutation. If you want to use Vuex integration on VueSocketIO, you need to add vuex object when declaring the VueSocketIO class.

Here’s the basic example for main.js

// Set Vue to use Vuex
Vue.use(Vuex);

// Create store
const store = new Vuex.Store({
  state: {
      someData: null
  },
  getters: {},
  actions: {
      "SOCKET_my response"(context, data) {
          // Received `my response`, do something with the data, in this case we are going to call mutation "setData"
        context.commit("setData", data);
      }
  }
  mutations: {
      ["setData"](state, data) {
          state.someData = data; // Set it to state
      }
  }
});

// Set Vue to use VueSocketIO with Vuex integration
Vue.use(new VueSocketIO({
  debug: true,
  connection: 'http://192.168.0.38:5000',
  vuex: {
      store,
      actionPrefix: "SOCKET_"
    }
}));

new Vue({
  router,
  store
  render: h => h(App)
}).$mount("#app");

If you need example on Vuex Integration, you can check my example app that uses Vue and Vue-Socket.io with Vuex integration.te