MetinSeylan / Vue-Socket.io

😻 Socket.io implementation for Vuejs and Vuex
https://metin.sh
MIT License
3.95k stars 496 forks source link

Feature request: Emit to socket from inside vuex store's mutations, actions functions #337

Open mzaiprog opened 2 years ago

mzaiprog commented 2 years ago

https://lukashermann.dev/writing/socketio-with-vue-and-vuex/

Layed out some way to emit to socket from inside vuex store's action functions. But would it not be nicer to have this feature here? And if it already exists, please add some example code to the docs.

Kind regards.

mzaiprog commented 2 years ago

From the vue-3-socket.io's source point of view, possibly injecting the socketIO instance into the vuex instance would break the design pattern. So I like to share this small code snippet, that solved my issue by injecting vue-3-socket.io into the vuex store via main.js:

main.js:

import { createApp } from "vue";

import App from "./App";
import store from "./store";
import socket from "./socket";

// inject vue-3-socket.io into the vuex store
store.$socket = socket;

const app = createApp(App);
app.use(store);
app.use(socket);
app.mount("#app"); 

Following is some usage Example:

store.js:

import { createStore } from "vuex";

export default createStore({
    state() {
        return {
            message: "default message",
        };
    },
    mutations: {
        SOCKET_updateMessage(state, message) {
            console.log("SOCKET_updateMessage: message:", message);
            state.message = message;
        },
        updateMessage(state, message) {
            console.log("updateMessage: message:", message);
            this.$socket.io.emit("fromClientStore", "updateMessage", message);
        },
    },
});

socket.js:

import SocketIO from 'socket.io-client';
import VueSocketIO from "vue-3-socket.io";

import store from "./store";

export default new VueSocketIO({
    debug: true,
    connection: SocketIO(),
    vuex: {
        store,
        actionPrefix: "SOCKET_",
        mutationPrefix: "SOCKET_",
    },
});

Express server's index.js:

import http from "http";
import expressCls from "express";
import { Server as SocketIOServer } from "socket.io";

class Server {
    clientSocket = null;

    constructor(port = 80) {
        // define network layer
        console.log("Server.constructor: (define network layer) port:", port);

        this.expressObj = expressCls();
        this.httpServer = http.createServer(this.expressObj);
        this.svrIO = new SocketIOServer(this.httpServer);
        this.svrIO.on("connection", (socket) => {
            console.log("svrIO.on: connection: socket.id:", socket.id);
            this.clientSocket = socket;

            socket.on("fromClientStore", (action, message) => {
                console.log("socket.on: fromClientStore/" + action + ": message:", message);
                server.clientSocket.emit("updateMessage", message);
            });

            socket.on("disconnect", (reason) => {
                console.log("socket.on: disconnect: socket.id:", socket.id, "reason:", reason);
            });
        });

        this.expressObj.use(expressCls.static("client/dist"));
        this.httpServer.listen(port, () => {
            console.log("Open your browser: http://localhost:" + port);
        });
    }
}
const server = new Server();

app.vue:

<template>
    <h1>$store.state.message: {{ $store.state.message }}</h1>
    <button @click.prevent="$store.commit('updateMessage', 'Button pressed')">updateMessage</button>
</template>