Skip to content
This repository was archived by the owner on Jun 18, 2025. It is now read-only.

provide useSocket() function #520

Open
wants to merge 6 commits into
base: alpha
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
node_modules/
npm-debug.log
.idea/
dist

# Release notes
RELEASE_NOTE*.md
Expand Down
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ app.use(VueSocketIOExt, socket);

## :rocket: Usage

#### On Vue.js component
#### On Vue.js component using the options API

Define your listeners under `sockets` section, and they will be executed on corresponding `socket.io` events automatically.

Expand All @@ -119,6 +119,39 @@ createApp({

**Note**: Don't use arrow functions for methods or listeners if you are going to emit `socket.io` events inside. You will end up with using incorrect `this`. More info about this [here](https://github.com/probil/vue-socket.io-extended/issues/61)

#### On Vue.js component using the Composition API

When using the `setup` option of the Composition API, `this` is not available. In order to use socket.io, two composables can be used. `useSocket()` gives you the same object as `this.$socket` would be. With `onSocketEvent(event, callback)` you can subscribe to a `socket.io` event. Subscription will happen before the component is mounted and the component will automatically unsubscribe right before it is unmounted.

```js
import { useSocket, onSocketEvent } from 'vue-socket.io-extended'

defineComponent({
setup() {
const socket = useSocket();

onSocketEvent('connect', () => {
console.log('socket connected')
});

onSocketEvent('customEmit', (val) => {
console.log('this method was fired by the socket server. eg: io.emit("customEmit", data)')
});

const clickButton = (val) => {
// socket.client is the `socket.io-client` instance
socket.client.emit('emit_method', val);
};

return {
clickButton
}
}
})
```

**Note**: Don't subscribe / unsubscribe from events (via `$subscribe()` / `$unsubscribe` provided by `useSocket()`) directly in `setup()`. Always do this from within a lifecycle hook like `onBeforeMount` or `onBeforeUnmount` or in a method that is called once the component is created. The `onSocketEvent` composable will do this automatically for you. The reason is, that the moment `setup()` is executed the component is not yet instantiated and `$subscribe` /`$unsubscribe` therefore can't bind to a component instance.

#### Dynamic socket event listeners (changed in v4)

Create a new listener
Expand Down
1 change: 0 additions & 1 deletion dist/vue-socket.io-ext.esm.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/vue-socket.io-ext.min.js

This file was deleted.

44 changes: 44 additions & 0 deletions src/__tests__/composables.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { mount } from '@vue/test-utils';
import { useSocket, onSocketEvent } from '../composables';
import Main from '../plugin';
import io from '../__mocks__/socket.io-client';

it('useSocket() injects $socket', () => {
let injectedSocketExtension;
const wrapper = mount({
render: () => null,
setup() {
injectedSocketExtension = useSocket();
},
}, { global: { plugins: [[Main, io('ws://localhost')]] } });
expect(injectedSocketExtension).toBe(wrapper.vm.$socket);
});

describe('onSocketEvent()', () => {
it('subscribes to the event', () => {
const spy = jest.fn();
const socket = io('ws://localhost');
mount({
render: () => null,
setup() {
onSocketEvent('event', spy);
},
}, { global: { plugins: [[Main, socket]] } });
socket.fireServerEvent('event', 'data');
expect(spy).toHaveBeenCalledWith('data');
});

it('unsubscribes before unmounted', () => {
const spy = jest.fn();
const socket = io('ws://localhost');
const wrapper = mount({
render: () => null,
setup() {
onSocketEvent('event', spy);
},
}, { global: { plugins: [[Main, socket]] } });
wrapper.unmount();
socket.fireServerEvent('event', 'data');
expect(spy).not.toHaveBeenCalled();
});
});
16 changes: 14 additions & 2 deletions src/__tests__/plugin.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mount } from '@vue/test-utils';
import { createApp } from 'vue';
import * as Main from '../plugin';
import { createApp, inject } from 'vue';
import { SocketExtensionKey } from '..';
import Main from '../plugin';
import io from '../__mocks__/socket.io-client';

it('should be vue plugin (is an object with `install` method)', () => {
Expand Down Expand Up @@ -96,6 +97,17 @@ describe('.install()', () => {
componentListener,
});
});

it('provides $socket to be injectable via the SocketExtensionKey symbol within setup()', () => {
let injectedSocketExtension;
const wrapper = mount({
render: () => null,
setup() {
injectedSocketExtension = inject(SocketExtensionKey);
},
}, { global: { plugins: [[Main, io('ws://localhost')]] } });
expect(injectedSocketExtension).toBe(wrapper.vm.$socket);
});
});

describe('.defaults', () => {
Expand Down
14 changes: 14 additions & 0 deletions src/composables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { inject, onBeforeMount, onBeforeUnmount } from 'vue';

const SocketExtensionKey = Symbol('$socket');

const useSocket = () => inject(SocketExtensionKey);

function onSocketEvent(event, callback) {
const socket = useSocket();
onBeforeMount(() => socket.$subscribe(event, callback));
onBeforeUnmount(() => socket.$unsubscribe(event));
}

export { SocketExtensionKey, useSocket, onSocketEvent };
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as plugin from './plugin';
import plugin from './plugin';

export default plugin;
export { SocketExtensionKey, useSocket, onSocketEvent } from './composables';
4 changes: 3 additions & 1 deletion src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import GlobalEmitter from './GlobalEmitter';
import createMixin from './createMixin';
import { isSocketIo } from './utils';
import defaults from './defaults';
import { SocketExtensionKey } from './composables';

/**
* @param {Vue} app
Expand Down Expand Up @@ -67,6 +68,7 @@ function install(app, socket, options) {
app.config.optionMergeStrategies.sockets = (toVal, fromVal) => ({ ...toVal, ...fromVal });
Observe(socket, options);
app.mixin(createMixin(GlobalEmitter));
app.provide(SocketExtensionKey, $socket);
}

export { defaults, install };
export default { defaults, install };
Loading