Skip to main content

Works with
JSR Score
58%
Published
2 weeks ago (1.0.2)

rocket-io

GitHub Actions Workflow Status NPM Version NPM Downloads NPM License JSR Version GitHub Repo stars

Wrapper for socket.io-client in ReactJs - works for React Native.

This package is using lbundle as bundler ✨

Install

NPM registry

# npm
npm i socket.io-client rocket-io

# yarn
yarn add socket.io-client rocket-io

# bun
bun install socket.io-client rocket-io

# pnpm
pnpm i socket.io-client rocket-io

JSR registry

# deno
deno add @mrii/rocket-io

# jsr
npx jsr add @mrii/rocket-io

Usage

Initialization

Call the createSocketHooks to get an instance of the hooks with the socket:

socket.io-hooks.ts

import { io } from 'socket.io-client';
import { createSocketHooks } from 'rocket-io';

const socketInstance = io(/* ... */);

// exports the hooks
export const {
  socket,
  useDisconnectOnUnmount,
  useSocket,
  useOn,
  useOnce,
  useEmit,
  useImmediateEmit,
  useEmitEffect,
} = createSocketHooks(socketInstance);

Alternative without io

you can pass io arguments to createSocketHooks and it will create the socket internally:

socket.io-hooks.ts

export const {
  /* ... */
} = createSocketHooks(url, options);

// or with only options
export const {
  /* ... */
} = createSocketHooks(options);

Alternative without initial socket - Lazy Initialization

you can delay the creating of the socket if you need information from the react tree, use useInitSocket to initialize it:

socket.io-hooks.ts

export const {
  useInitSocket,
  /* ... */
} = createSocketHooks();

Later on in the App

app.tsx

/* ... */

const App: React.FC = () => {
  /* ... */

  useInitSocket('<url>', { auth: { token } });

  // if the token isn't ready, or you don't want to initialize the socket yet, pass the `ready` arg

  useInitSocket('<url>', { auth: { token } }, isReady);

  /* ... */
};

Using the hooks

component.tsx

/* ... */

export const Component: React.FC = () => {
  /* ... */

  useOn(
    'event',
    useCallback(data => {
      console.log('[event] fired with: ', data);
    }, [])
  );

  useImmediateEmit('event-2', 'event-2 fired immediately');

  const emit = useEmit();
  /* ... */

  return <button onClick={() => emit('event', 'event data')}>emit event</button>;
};

TypeScript Support

You can pass your events map to createSocketHooks to provide you with safe listeners and emission events:

socket.io-hooks.ts

export type EmitEvents = {
  send_message: (message: string) => void;
};

export type ListenEvents = {
  message: (message: string) => void;
};

export const {
  /* ... */
} = createSocketHooks<EmitEvents, ListenEvents>();

component.tsx

/* ... */

export const Component: React.FC = () => {
  /* ... */

  useOn(
    /* typed! */
    'message',

    /* data type is provided! */
    useCallback(data => {
      console.log('[message] fired with: ', data);
    }, [])
  );

  useImmediateEmit(
    /* typed! */
    'send_message',

    /* emit arguments type is provided! */
    'message'
  );
};

Examples

Eager Initialization - casual applications

create and export the hooks:

socket.io-hooks.ts

import { createSocketHooks } from 'rocket-io';

// exports the hooks
export const {
  socket,
  useDisconnectOnUnmount,
  useSocket,
  useOn,
  useOnce,
  useEmit,
  useImmediateEmit,
  useEmitEffect,
} = createSocketHooks('<url>', {
  /* options */
});

disconnect on application unmount:

app.tsx

/* ... */

const App: React.FC = () => {
  /* ... */

  useDisconnectOnUnmount();

  /* ... */
};

use the hooks:

component.tsx

/* ... */

export const Component: React.FC = () => {
  /* ... */

  // listen to event
  useOn(
    'event',
    useCallback(data => {
      console.log('[event] fired with: ', data);
    }, [])
  );

  // listen to event once
  useOn(
    'ready',
    useCallback(() => {
      console.log('[ready] event fired');
    }, [])
  );

  // emit event when `Component` mounts
  useImmediateEmit('event-2', 'event-2 fired immediately');

  // emit event when dependencies array changes - similar to `useEffect(, deps)`
  useImmediateEmit([message], 'event-3', 'event-3 fired with new message: ' + message);

  // get emit function
  const emit = useEmit();

  /* ... */

  return <button onClick={() => emit('event', 'event data')}>emit event</button>;
};

Lazy Initialization - authorized sockets

create and export the hooks:

socket.io-hooks.ts

import { createSocketHooks } from 'rocket-io';

// exports the hooks
export const {
  useInitSocket,
  useDisconnectOnUnmount,
  useSocket,
  useOn,
  useOnce,
  useEmit,
  useImmediateEmit,
  useEmitEffect,
} = createSocketHooks();

initialize the socket once args is ready:

app.tsx

/* ... */

const App: React.FC = () => {
  /* ... */

  useInitSocket('<url>', { auth: { token } }, typeof token === 'string');

  useDisconnectOnUnmount();

  /* ... */
};

and then use the hooks normally

Multiple Sockets

you can create two socket hooks by calling createSocketHooks:

admin-socket-hooks.ts

import { createSocketHooks } from 'rocket-io';

export const adminSocketHooks = createSocketHooks('<admin-url>', {
  /* admin options */
});

products-socket-hooks.ts

import { createSocketHooks } from 'rocket-io';

export const productsSocketHooks = createSocketHooks('<products-url>', {
  /* products options */
});

API

socket

the socket in case you initialized it using createSocketHooks.

type Socket<TListenEvents, TEmitEvents>.

it will be undefined in case of Lazy Initialization.


useInitSocket

hook to init your socket in the app in case of Lazy Initialization.

Property Type Default Description Version
arg0:uri string undefined socket uri (io(uri)) 0.0.1
arg1:options Partial<ManagerOptions & SocketOptions>? undefined socket options (io(, options)) 0.0.1
arg2:start boolean? true start initializing the socket 0.0.1

return: void


useDisconnectOnUnmount

hook to disconnect and destroy the socket instance on unmounting, use in your root app if needed.

take no args

return: void


useSocket

hook that returns the instance of the socket.

take no args

return: Socket<TListenEvents, TEmitEvents>

it might return undefined in case of Lazy Initialization


useOn

hook to listen on every event emission.

Property Type Default Description Version
arg0:key string undefined event key to listen on (socket.on(key)) 0.0.1
arg1:listener Function undefined listener that will will be called when the event fires (socket.on(, listener)) 0.0.1

return: void


useOnce

hook to listen once on event emission.

Property Type Default Description Version
arg0:key string undefined event key to listen on (socket.once(key)) 0.0.1
arg1:listener Function undefined listener that will will be called when the event fires (socket.once(, listener)) 0.0.1

return: void


useEmit

hook that return the socket.emit function, or a lazy emission function in case of Lazy Initialization,

lazy emission function will emit if socket is available, or record event until the socket is available.

take no args.

return: socket.emit function.


useImmediateEmit

hook to emit an event once.

Property Type Default Description Version
arg0:key string undefined event key to emit (socket.emit(key)) 0.0.1
...args unknown[] undefined extra arguments to emit them (socket.emit(, ...args)) 0.0.1

return: void


useEmitEffect

hook to emit an event on mount and once the dependency array changes.

Property Type Default Description Version
arg0:deps unknown[] undefined dependency array to listen on (like useEffect(, deps)) 0.0.1
arg1:key string undefined event key to emit (socket.emit(key)) 0.0.1
...args unknown[] undefined extra arguments to emit them (socket.emit(, ...args)) 0.0.1

return: void

NOTES

  • try to use the hooks (useEmit, useOn, ...) instead of getting the socket from useSocket and use it, because there some extra cases handled in those hooks.

  • useInitSocket will not reinitialize the socket in case it's already initialized, utilize the third argument ready to indicate when you have all of the required properties to start initializing.

  • memoize the following arguments (not memoizing them may cause some unexpected behavior):

    • the listener passed to useOn and useOnce.
Built and signed on
GitHub Actions
View transparency log

Add Package

deno add @mrii/rocket-io

Import symbol

import * as mod from "@mrii/rocket-io";

Add Package

npx jsr add @mrii/rocket-io

Import symbol

import * as mod from "@mrii/rocket-io";

Add Package

yarn dlx jsr add @mrii/rocket-io

Import symbol

import * as mod from "@mrii/rocket-io";

Add Package

pnpm dlx jsr add @mrii/rocket-io

Import symbol

import * as mod from "@mrii/rocket-io";

Add Package

bunx jsr add @mrii/rocket-io

Import symbol

import * as mod from "@mrii/rocket-io";