npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@bucky24/redux-websocket

v0.3.4

Published

Uses a websocket to sync redux actions to a server and to other clients to keep them in sync.

Downloads

25

Readme

redux-websocket

Installation

With NPM

npm install --save @bucky24/redux-websocket

With Yarn

yarn install @bucky24/redux-websocket

What is it?

redux-websocket is a module that allows for a easy to setup sync of state between multiple clients. It does this by hooking directly into Redux and broadcasting every redux dispatch to any remote clients that are connected, as well as receiving dispatch updates from those clients, allowing all clients to stay in sync.

Usage

redux-websocket has two parts, the server and the client. Both are relatively simple to insert into an application, though the server is certainly simpler.

Server

To start the redux-websocket server, just run the following code:

const ReduxSocketServer = require('@bucky24/redux-websocket/server');

const PORT = process.env.port || 5000;

ReduxSocketServer(PORT);

And that's about it! The server will log various messages to the console as it sees connections come and go.

Client

Setting up the redux client is a bit more complex. The client must be aware of the redux store, however the client must be created before the redux store. This is because the client will inject the current working state into redux when a new user connects, which is important to ensure clients stay up to date.

In order to create a simple redux-websocket client with a redux store, use the following code:

import { ReduxWebSocketClient, SpecialActionType } "@bucky24/redux-websocket";
import React from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { render } from 'react-dom';

import reducers from './reducerRoot.js';
import App from './App';

const url = "ws://localhost:5000";
const protocol = "protocol";
const sessionID = "session";

const socketHandler = new ReactWebSocketClient(url, protocol);

socketHandler.setAuthentication(sessionID);
socketHandler.setReducers(reducers);

socketHandler.on('stateReceived', ({ initialState, reducers }) => {
	const store = createStore(
		reducers, initialState, applyMiddleware(socketHandler.getMiddleware())
	);

	render(
		<Provider store={store}>
			<App />
		</Provider>,
		document.getElementById('root')
	);
	
	return store;
});

Client Options

The client can treat different actions and parts of the state tree differently. Perhaps you want certain actions or parts of the state to not sync to all clients. Or perhaps you want certian actions or parts of the state to sync to clients, but for each client to maintain their own state, and not have it overwritten by others.

Ignored State

Actions that are ignored are not broadcast to other clients, and state tree that is ignored is stripped out by the master connection when giving the initial state for a client.

To add ignored state, you'll need to do the following in the client:

import { ReduxWebSocketClient, SpecialActionType } from "@bucky24/redux-websocket";
// ... other imports

const socketHandler = new ReactWebSocketClient(url, protocol, {
	specialActions: [
		{
			type: SpecialActionType.IGNORED,
			actions: [Constants.SET_SAMPLE_2],
			tree: ['top_level_state_tree'_],
		},
	]
});

User State

Actions that are part of the user state are still broadcast to other clients, but are not stored in the main redux state. Instead, the changed data is stored under another branch of the state, under the user's connection ID, so that it can be referred to in context of that user. An example of where this might be useful is information specific to a user, like a name.

To add user state, you'll need to add the following to the client init code:

import { ReduxWebSocketClient, SpecialActionType } from "@bucky24/redux-websocket";
// ... other imports

const socketHandler = new ReactWebSocketClient(url, protocol, {
	specialActions: [
		{
			type: SpecialActionType.USER_DATA,
			actions: [Constants.SET_SAMPLE_2],
			tree: ['top_level_state_tree'_],
		},
	]
});

You'll also need to add the websocket reducer into your reducer root, as redux-websocket uses the redux store to store user data (as well as some internal connection data)

import { combineReducers } from 'redux';
import { WebSocketReducer } from '@bucky24/redux-websocket';
import sample from './store';

// reducers here

const reducers = {
	sample,
	__websocket: WebSocketReducer,
};

export default combineReducers(reducers);

Note that __websocket must be the name of the reducer.

In order to extract and use the websocket user data, you can use the helpful selectors provided by the client.

import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { getUserData } from '@bucky24/redux-websocket';

import styles from './styles.css';

const App = ({
	userData,
}) => {	
	return (<div className={styles.appRoot}>
		{ Object.keys(userData).map((id) => {
			const data = userData[id];
			
			return <div key={id}>
				{ data.user.name }: { id }
			</div>;
		})}
	</div>);
};

const mapStateToProps = (state) => {
	return {
		userData: getUserData(state),
	};
};

const mapDispatchToProps = (dispatch) => {
	return {

	};
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

Handling Session Codes After App Init

It may be very useful to have your user not enter the code until later. This could be because you want to show them some UI before entering a code. Or, in the case of the first user to enter, perhaps you want to auto-generated the code that they need to share to other users.

This gets somewhat complicated because the socket handler itself needs to create the main Redux store (due to setting initial state). This means you won't be able to use your main store until the user has entered the code, so this should be among the first things your application does.

See the delayed_connect_example for a more in-depth example on how to do this.

Essentially, your socket handler should be created in a way that can be acessed by your UI. Use the following code in your main app index:

import socketHandler from './path/to/your/handler';

socketHandler.on('stateReceived', ({ initialState, reducers }) => {
	// your normal app initialization, as above
});

render(
	<PreSocketApp/>,
	document.getElementById('root')
);

Then inside PreSocketApp, somewhere you would need to have:

import socketHandler from './path/to/your/handler';

class PreSocketApp extends React.Component {
	handleSubmit(code) {
		socketHandler.setAuthentication(code);
	}
	
	// the rest of the class
}

At this point, the system will attempt to authenticate with that code, and will load the correct initial state from the server. The main app initialization will fire, and the page will be reloaded.

Fetching State

At any point, from the server, you can fetch the current state for any session by calling the getState method on the server socket.

import socket from './path/to/your/handler';

async function foo() {
	const state = await socket.getState();
}

Event Handling

The socket server will emit various events. To listen for them, use the on method:

import socket from './path/to/your/handler';

socket.on(event, (data) => {
	// do something
});

The various event types and the data they return can be found below: | Event | When | Callback Data | | ---- | ------ | ---- | | message | Fired when the websocket gets a message it does not know how to process. | An object containing "message" and "id" (being the ID of the connection that fired the message) | | getInitialState | Fired when the first socket connects for a session. From here you can return an object that will make up the initial state passed into redux. Response can be a promise. | An object containining "session" |

Custom Messages

The websocket frontend client can be told to fire a custom message to the server. Such a message can be listened to with the "message" event handler.

import socket from './socket';

socket.sendMessage(messageType, data);

Similar Modules

The main module I have seen that appears similar is https://github.com/giantmachines/redux-websocket

The main difference here is that @giantmatchines/redux-websocket (and similar packages) uses redux to control the websocket, while @bucky24/redux-websocket uses the websocket to control redux.