Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guidance on Creating a Socket Cluster Client Connection with Redux Toolkit or RTK Query #4451

Closed
RezaBakhshiNia opened this issue Jun 12, 2024 · 3 comments

Comments

@RezaBakhshiNia
Copy link

Hello Redux Toolkit Team,

I am currently working on a project that involves setting up a socket cluster client connection to handle multiple channels and read data from each channel without sending any data. I have been exploring ways to integrate this functionality with Redux Toolkit or RTK Query to manage the state effectively.

I would greatly appreciate your guidance on the best approach to create a middleware or utilize RTK Query to establish and manage a socket cluster client connection that can subscribe and handle multiple channels and efficiently read data from each channel.

Any insights, code examples, or recommended practices you could provide would be immensely helpful in advancing my project.

Thank you for your time and support. I look forward to your valuable assistance.

Best regards.

@phryneas
Copy link
Member

I'm afraid without some code examples of things you have tried it's going to be hard to point out ways you can improve those approaches.

@RezaBakhshiNia
Copy link
Author

RezaBakhshiNia commented Jun 12, 2024

I'm afraid without some code examples of things you have tried it's going to be hard to point out ways you can improve those approaches.

// socket.js

import socketClusterClient from "socketcluster-client";
import { BASE_URL } from "./endpoints";

export const socket = socketClusterClient.create({
  hostname: BASE_URL,
  port: 443,
  secure: true,
});

// clusterMiddleware.js

const onSocketConnect = async (channel, dispatch) => {
  for await (let data of channel) {
    console.log(data);
    dispatch(saveData(data));
  }
};


export const socketMiddleware = () => {
  let channels = {};

  return (store) => (next) => (action) => {
    switch (action.type) {
      case SUBSCRIBE:
        if (socket) {
          const { channelName } = action.payload;
          if (!channels[channelName]) {
            const channel = socket.channel(channelName);
            if (channel.isSubscribed()) return;
            channels[channelName] = channel;
            channel.subscribe();
            channel.listener("subscribe").once();
            onSocketConnect(channel, store.dispatch);
          }
        }
        break;

      case UNSUBSCRIBE:
        if (socket) {
          const channelName = action.payload;
          if (channels[channelName]) {
            socket.unsubscribe(channelName);
            delete channels[channelName];
          }
        }
        break;

      default:
        return next(action);
    }
  };
};

// store.js

export const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false,
    }).concat(socketMiddleware),
});

export const persistor = persistStore(store);

I am currently experiencing an issue where the application only displays a white screen without any accompanying error messages in the console. Upon inspecting the network tab, I can see that the connection is successful with responses being received; however, the application fails to render any content.

This project is built using Vite.js as the bundler for the React application.

@RezaBakhshiNia
Copy link
Author

I've managed to resolve the issue I was facing. The solution involved declaring the socketClusterClient inside the middleware and using an Immediately Invoked Function Expression (IIFE) for data retrieval.

// socketMiddleware.js
import { connectSuccess, connectError, createChannelData } from "./socketSlice";
import * as socketClusterClient from "socketcluster-client";

const socketMiddleware = (store) => {
  let socket;

  const handleSocketEvents = async () => {
    for await (const event of socket.listener("connect")) {
      store.dispatch(connectSuccess(event));
    }
    for await (const event of socket.listener("error")) {
      store.dispatch(connectError(event));
    }
  };

  return (next) => (action) => {
    switch (action.type) {
      case "socketCluster/connect": {
        socket = socketClusterClient.create(action.payload);
        handleSocketEvents();
        break;
      }
      case "socketCluster/subscribe": {
        if (socket) {
          const channelName = action.payload;
          const channel = socket.subscribe(channelName);
          (async () => {
            for await (const data of channel) {
              store.dispatch(
                createChannelData({ channelName: channelName, data: data })
              );
            }
          })();
        }
        break;
      }
      case "socketCluster/unsubscribe": {
        if (socket) {
          const channelName = action.payload;
          socket.unsubscribe(channelName);
        }
        break;
      }
      default:
        break;
    }
    return next(action);
  };
};

export default socketMiddleware;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants