Skip to content
Merged
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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,22 @@ If used, an [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/Event
- There is no 'CLOSING' readyState for `EventSource`, and as such, the CLOSED readyState is `2` for an `EventSource`, whereas it is `3` for a WebSocket. For purposes of internal consistency, the `readyState` returned by `useWebSocket` will follow the `WebSocket` enumeration and use `3` for the CLOSED event for both instance types.
- `getEventSource` will return the underlying EventSource, even if `Options#share` is used -- as opposed to the `WebSocket` equivalent which returns a `Proxy`.
- There is no concept of sending messages from the client, and as such `sendMessage` will not be provided.

### Reset Global State
There are some cases when the global state of the library won't reset with the page. The main behavior relies on the fact that a single page application operates only in one window, but some scenarios allow us to make a new window via `window.open` and inject code there. In that case, child window will be closed, but the global state of the library remains the same in the main window. This happens because react does not finish components lifecycle on window close.

To avoid troubles with the new initialization of components related to the same URL, you can reset the global state for a specific connection based on your own logic.

```js
import React, { useEffect } from 'react';
import { resetGlobalState } from 'react-use-websocket';

// insside second window opened via window.open
export const ChildWindow = () => {
useEffect(() => {
window.addEventListener("unload", () => {
resetGlobalState('wss://echo.websocket.org');
});
}, []);
}
```
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export { useSocketIO } from './lib/use-socket-io';
export { ReadyState } from './lib/constants';

export { useEventSource } from './lib/use-event-source';

export { resetGlobalState } from './lib/util';
33 changes: 33 additions & 0 deletions src/lib/globals.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {sharedWebSockets, resetWebSockets} from './globals';
import {WebSocketLike} from './types';

const FIRST_URL = 'ws://localhost:1234';
const SECOND_URL = 'ws://localhost:4321';

const websocket1 = {} as WebSocketLike;
const websocket2 = {} as WebSocketLike;

beforeEach(() => {
resetWebSockets();
});

test('resetWebsockets removes subscribers only for a specific URL', () => {
sharedWebSockets[FIRST_URL] = websocket1;
sharedWebSockets[SECOND_URL] = websocket2;
expect(Object.values(sharedWebSockets)).toHaveLength(2);

resetWebSockets(FIRST_URL);

expect(sharedWebSockets[FIRST_URL]).toBeUndefined();
expect(sharedWebSockets[SECOND_URL]).not.toBeUndefined();
});

test('resetWebsockets removes all subscribers when URL is not set', () => {
sharedWebSockets[FIRST_URL] = websocket1;
sharedWebSockets[SECOND_URL] = websocket2;
expect(Object.values(sharedWebSockets)).toHaveLength(2);

resetWebSockets();

expect(Object.values(sharedWebSockets)).toHaveLength(0);
});
12 changes: 12 additions & 0 deletions src/lib/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,15 @@ export interface SharedWebSockets {
}

export const sharedWebSockets: SharedWebSockets = {};

export const resetWebSockets = (url?: string): void => {
if (url && sharedWebSockets.hasOwnProperty(url)) {
delete sharedWebSockets[url];
} else {
for (let url in sharedWebSockets){
if (sharedWebSockets.hasOwnProperty(url)){
delete sharedWebSockets[url];
}
}
}
}
32 changes: 32 additions & 0 deletions src/lib/manage-subscribers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import {
hasSubscribers,
addSubscriber,
removeSubscriber,
resetSubscribers,
} from './manage-subscribers';
import { Subscriber } from './types';

const URL = 'ws://localhost:1234';
const SECOND_URL = 'ws://localhost:4321'
const noop = () => {};

const subscriber1: Subscriber = {
Expand Down Expand Up @@ -66,3 +68,33 @@ test('removeSubscriber removes a subscriber from a url subscription', () => {
removeSubscriber(URL, subscriber2);
expect(getSubscribers(URL)).toHaveLength(0);
});

test('resetSubscribers removes subscribers only for a specific URL', () => {
addSubscriber(URL, subscriber1);
addSubscriber(URL, subscriber2);
expect(getSubscribers(URL)).toHaveLength(2);

addSubscriber(SECOND_URL, subscriber1);
addSubscriber(SECOND_URL, subscriber2);
expect(getSubscribers(SECOND_URL)).toHaveLength(2);

resetSubscribers(URL);

expect(getSubscribers(URL)).toHaveLength(0);
expect(getSubscribers(SECOND_URL)).toHaveLength(2);
});

test('resetSubscribers removes all subscribers when URL is not set', () => {
addSubscriber(URL, subscriber1);
addSubscriber(URL, subscriber2);
expect(getSubscribers(URL)).toHaveLength(2);

addSubscriber(SECOND_URL, subscriber1);
addSubscriber(SECOND_URL, subscriber2);
expect(getSubscribers(SECOND_URL)).toHaveLength(2);

resetSubscribers();

expect(getSubscribers(URL)).toHaveLength(0);
expect(getSubscribers(SECOND_URL)).toHaveLength(0);
});
13 changes: 13 additions & 0 deletions src/lib/manage-subscribers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Subscriber } from './types';
import {sharedWebSockets} from "@lib/globals";

export type Subscribers = {
[url: string]: Set<Subscriber>,
Expand Down Expand Up @@ -26,3 +27,15 @@ export const addSubscriber = (url: string, subscriber: Subscriber): void => {
export const removeSubscriber = (url: string, subscriber: Subscriber): void => {
subscribers[url].delete(subscriber);
};

export const resetSubscribers = (url?: string): void => {
if (url && subscribers.hasOwnProperty(url)) {
delete subscribers[url];
} else {
for (let url in subscribers){
if (subscribers.hasOwnProperty(url)){
delete subscribers[url];
}
}
}
}
8 changes: 8 additions & 0 deletions src/lib/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { WebSocketLike } from './types';
import {resetWebSockets} from './globals';
import {resetSubscribers} from './manage-subscribers';

export function assertIsWebSocket (
webSocketInstance: WebSocketLike,
): asserts webSocketInstance is WebSocket {
if (webSocketInstance instanceof WebSocket === false) throw new Error('');
};


export function resetGlobalState (url?: string): void {
resetSubscribers(url);
resetWebSockets(url);
};