1.2.0 • Published 4 years ago

redux-signalr v1.2.0

Weekly downloads
218
License
MIT
Repository
github
Last release
4 years ago

Redux middleware for SignalR (ASP.NET Core)

Installation

npm install redux-signalr

or

yarn add redux-signalr

Usage

NOTE: You don't need to install @microsoft/signalr as it's already included in this package for convenience and exports all the code from @microsoft/signalr. Also, apart of SignalR invoke method, redux-signalr gives you an access to Redux state and dispatch in actions, so you don't need to use redux-thunk and redux-signalr simultaneously as the latter already does the same job.

First, configuration

Build a connection object

const connection = new HubConnectionBuilder()
  .configureLogging(LogLevel.Debug)
  .withUrl('https://0.0.0.0:5001/testHub', {
    skipNegotiation: true,
    transport: HttpTransportType.WebSockets,
  })
  .build();

Register callbacks

In the callbacks you have an access to redux dispatch and getState and signalr invoke methods.

const callbacks = withCallbacks()
  .add('ReceiveMessage', (msg: string) => (dispatch) => {
    dispatch(setText(msg));
  })
  .add('ReceiveRandomNumber', (num: number) => (dispatch, getState, invoke) => {
    const { example } = getState();
    dispatch(setRandomNumber(num));
    invoke('SendMessage', txt + example.text)
  })

Create middleware with the callbcaks and connection object

export const signal = signalMiddleware({
  callbacks,
  connection,
});

Second, apply the configured middleware

import { signal } from './helpers/withSignalR';

export default function configureStore(preloadedState?: RootState) {
  return createStore(
    rootReducer,
    preloadedState,
    applyMiddleware(signal)
  );
}

Third, write action functions as you would do with thunk, but now it has the third parameter - invoke (from signalR) to call server methods

export const sendMessage = (txt: string): Action => (dispatch, getState, invoke) => {
  invoke('SendMessage', txt)
};

Fourth (only for TS), add custom types

import { rootReducer } from './rootReducer';
import { AnyAction } from 'redux';
import { SignalAction, SignalDispatch } from 'redux-signalr';

export type RootState = ReturnType<typeof rootReducer>;

export type Action<ReturnValue = void> = SignalAction<
  ReturnValue,
  RootState,
  AnyAction
>;

export type Dispatch<Action extends AnyAction = AnyAction> = SignalDispatch<
  RootState,
  Action
>;

Use those Dispatch and RootState types in callbacks, this way you will have correct typings for dispatch and getState methods in your callbacks

const callbacks = withCallbacks<Dispatch, RootState>()
  .add('CallbackName', () => (dispatch, getState, invoke) => { }

Additional features

Don't start a connection immediately

Create signalMiddleware with shouldConnectionStartImmediately set to false.

const signal = signalMiddleware({
  callbacks,
  connection,
  shouldConnectionStartImmediately: false
});

Then, import the 'connection' in the place you want and start it if it's not already. Here is an example with a simple Button container:

import { connection } from "../redux/helpers/createSignalMiddleware";

const StartConnectionButton: FunctionComponent = () => {
  const handleClick = useCallback(() => {
    if (connection.state !== HubConnectionState.Connected) {
      connection
        .start()
        .then(() => console.log("Connection started"))
        .catch((err) => console.error(err.toString()));
    }
  }, []);

  return <Button onClick={handleClick}>Start Connection</Button>;
};

export default StartConnectionButton;
1.2.0

4 years ago

1.1.0

4 years ago

1.1.0-alpha.0

4 years ago

1.0.0

4 years ago

0.0.7

4 years ago

0.0.5

4 years ago

0.0.6

4 years ago

0.0.3

4 years ago

0.0.4

4 years ago

0.0.2

4 years ago

0.0.1

4 years ago