nathantsoi / vue-native-websocket

native websocket with vuex integration
943 stars 162 forks source link

Listener example #30

Open flip111 opened 6 years ago

flip111 commented 6 years ago

How can i use onmessage or onopen in my Vue component? I have vue-native-websocket and vuex already setup. I know i should use this code https://github.com/nathantsoi/vue-native-websocket#dynamic-socket-event-listeners but where?

flip111 commented 6 years ago

Found this, but don't really understand it https://forum.vuejs.org/t/referencing-vue-instance-in-vuex/14678/9 in the end the guy doesn't seem to use the vue-native-websocket anymore though

import WebSocket from 'simple-websocket'
Vue.prototype.$ws = new WebSocket('URL')
anthu commented 6 years ago

Maybe this helps:

assign your function to the listener in the created method of your Component:

  created () {
    this.$options.sockets.onmessage = (data) => this.messageReceived(data)
  },
flip111 commented 6 years ago

Thank you @anthu ! by the way .. since then i also found another method to get the value in a template

  computed: {
    socketMessage() {
      return this.$store.state.message
    },
  },
<template>
  <div>{{socketMessage}}</div>
</template>

Perhaps both methods can be added to the readme?

flip111 commented 6 years ago

is it better to get the data from the argument to the messageReceived function or to access the vuex store?

flip111 commented 6 years ago

@anthu i heard that doing this.$options and then an assignment is not a good way to do things because $options is read-only .. but i'm very new to vue and i don't know if this could cause problems or what is the better way to do this ...

EDIT: "this.$options is immutable but this.$options.socket.onmessage isn't"

flip111 commented 6 years ago

If i start using this listener this.$options.sockets.onmessage = (data) => console.log(data) and then access the store which has been filled with state.message = message i'm always 1 behind with the actual data. I reopen this issue because i think this part of the library could use some best practice recommendation.

store.js

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

Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
    socket: {
      isConnected: false,
      message: '',
      reconnectError: false
    },
    message: {
      awesome: ''
    }
  },
  mutations: {
    SOCKET_ONOPEN (state, event) {
      state.socket.isConnected = true
    },
    SOCKET_ONCLOSE (state, event) {
      state.socket.isConnected = false
    },
    SOCKET_ONERROR (state, event) {
      console.error(state, event)
    },
    // default handler called for all methods
    SOCKET_ONMESSAGE (state, message) {
      console.log('message in store', message.regs)
      state.message = message
    },
    // mutations for reconnect methods
    [WebSocket.WS_RECONNECT](state, count) {
      console.info(state, count)
    },
    [WebSocket.WS_RECONNECT_ERROR](state) {
      state.socket.reconnectError = true
    }
  }
})

Socket.vue

<template>
  <div>
    <p v-if="isConnected">We're connected to the server!</p>
    <p>{{r.reg1}}</p>
    <p>{{r.reg2}}</p>
    <p>{{r.reg3}}</p>
    <button @click="start()">start</button>
    <button @click="stop()">stop</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isConnected: false,
      regnames: [],
      r: []
    }
  },

  created() {
    // todo: get regnames dynamically
    var regnames = ['reg1', 'reg2', 'reg3']

    regnames.forEach((name) => {
      this.regnames.push(name)
      this.r[name] = 0
    })

    this.$options.sockets.onmessage = (data) => this.messageReceived(data)
  },

  methods: {
    messageReceived: function(raw_message) {
      var p = this.$store.state.message.regs

      console.log(raw_message)
      for (var regname in p) {
        console.log(regname + ': ' + p[regname])
        if (p.hasOwnProperty(regname)) {
          this.r[regname] = p[regname]
        }
      }

      this.$forceUpdate()
    },
    start() {
      this.$socket.sendObj({command: 'start'})
    },
    stop() {
      this.$socket.sendObj({command: 'stop'})
    }
  }
}
</script>

console output

Socket.vue?3af7:38 MessageEvent {isTrusted: true, data: "{"regs": {"reg1": 1, "reg2": 2, "reg3": 3}}", origin: "ws://localhost:8080", lastEventId: "", source: null, …}
store.js?a259:29 message in store {reg1: 1, reg2: 2, reg3: 3}
Socket.vue?3af7:38 MessageEvent {isTrusted: true, data: "{"regs": {"reg1": 2, "reg2": 4, "reg3": 6}}", origin: "ws://localhost:8080", lastEventId: "", source: null, …}
Socket.vue?3af7:40 reg1: 1
Socket.vue?3af7:40 reg2: 2
Socket.vue?3af7:40 reg3: 3
store.js?a259:29 message in store {reg1: 2, reg2: 4, reg3: 6}
Socket.vue?3af7:38 MessageEvent {isTrusted: true, data: "{"regs": {"reg1": 3, "reg2": 6, "reg3": 9}}", origin: "ws://localhost:8080", lastEventId: "", source: null, …}
Socket.vue?3af7:40 reg1: 2
Socket.vue?3af7:40 reg2: 4
Socket.vue?3af7:40 reg3: 6
store.js?a259:29 message in store {reg1: 3, reg2: 6, reg3: 9}

By message in store you can see the store gets the websocket events in the right order. And by Socket.vue?3af7:38 you can see that messageReceived is also getting the RAW websocket message in the right order. But triggering this way doesn't make the local state update to the new state which is in the store. I noticed this because i'm missing this in my console output:

Socket.vue?3af7:40 reg1: 7
Socket.vue?3af7:40 reg2: 8
Socket.vue?3af7:40 reg3: 9
ghost commented 6 years ago

index.vue?3c8f:38 Uncaught TypeError: Cannot read property 'regs' of undefined

ghost commented 5 years ago

Inside one of my vue component I am trying to add a websocket listener like this:

`... , created() {

//this.$options.sockets.onmessage = function (data) { this.messageReceived(data) }
this.$options.sockets.onmessage = data => this.messageReceived(data);

},... methods: { messageReceived(raw_message) { console.log("raw_message: " + raw_message); } } ` It works fine on chrome but not on IE11. On IE I get the following error (sorry in french):

[Vue warn]: Error in created hook: "TypeError: Impossible de définir la propriété « onmessage » d’une référence null ou non définie"

It means: Cannot define property onmessage from a null or undefined reference. First I thought it was because of arrow function but even when I try without it I have the same error. Any idea ?

ranhao1 commented 4 years ago

@vrichomme maybe this helps:

beforeCreate() {
    this.$options.sockets = {
      onmessage: data => this.messageReceived(data)
    }
  }