You need to enable JavaScript to run this app.

useSocket

A hook to use socket in a more linear and reactive way

Source

// /contexts/chat.js

import { useState, useEffect, useCallback, useRef } from "react";
import socketIOClient from "socket.io-client";
import { createContext, useContextSelector } from "use-context-selector";

const socketBaseURL = "...";

const SocketContext = createContext();

export default function SocketProvider({ children }) {
  const user = "USER_ID_FROM_GLOBAL_STATE";

  const [isConnected, setConnected] = useState(false);
  const [isActive, setActive] = useState(false);

  const socketRef = useRef(null);

  useEffect(() => {
    if (!socketRef.current) {
      const token = "AUTH_TOKEN";

      socketRef.current = socketIOClient(socketBaseURL, {
        transports: ["websocket"],
        query: { token },
      });

      socketRef.current.on("connect", () => setConnected(true));

      socketRef.current.on("disconnect", () => setConnected(false));

      socketRef.current.on("SOME_EVENT", (message) => {
        // do stuff
      });

      socketRef.current.on("error", () => {});
    }

    return () => {
      if (socketRef.current) resetConnection();
    };
  }, []);

  const resetConnection = () => {
    if (socketRef.current) socketRef.current.disconnect();

    socketRef.current = null;
  };

  const contextValue = {
    isConnected,
    isActive,

    // some other methods

    resetConnection,
    ref: socketRef,
  };

  return (
    <SocketContext.Provider value={contextValue}>
      {children}
    </SocketContext.Provider>
  );
}

Hook

Instead of doing this in every file:

import { useContextSelector } from "use-context-selector";
import SocketContext from "@contexts/chat";

function Component(props) {
  const chat = useContextSelector(SocketContext, ...);
}

You can create a hook that does this and you just need to import that one hook in your files:

import { useContextSelector } from "use-context-selector";
import SocketContext from "@context/Socket";

const useSocket = (selector) => {
  const context = useContext(SocketContext, selector);

  if (isDevelopment && context === undefined)
    throw new Error("useSocket must be used within a SocketProvider");

  return context;
};

export default useSocket;

This doesn't do anything right now, it's just a way to skip multiple imports and also it gives us some flexibility in the future and makes our code future proof.

Usage

const Chat = function (props) {
  const socket = useSocket((state) => state.isActive);

  return <div>...</div>;
};
Favourite Books
BooksPoems
Favourite Songs
PlaylistsArtists
Favourite Shows
AnimationsSeriesAnime