Search code examples
reactjssocket.ioreact-context

Using context within another context


So I have these 2 contexts, UserContext and SocketContext. The problem is -- I need to pass the user's details (mobile number) to the socket context so when the socket initializes it automatically joins the required room.

This is what app.js looks like:

function App() {

  const [user, setUser] = useState(null);

  useEffect(() => {
    (async () => {
      const res = await fetch("/api/me", {
        credentials: "include"
      })
      if (res.status === 200) {
        const json = await res.json()
        setUser(json.user)
      }
    })();    
  }, [])

  return (
    <UserContext.Provider value={user}>
      <SocketContext.Provider value={socket}>
        <Switch>
          ... routes
        </Switch>
      </SocketContext.Provider>
    </UserContext.Provider>
  )
}

export default App;

I am fetching the user when the component loads and setting the value to the user which is then passed to the user context.

UserContext

export const UserContext = createContext(null);

SocketContext:

import { io } from "socket.io-client";

const socket = io("http://localhost:3000", { autoConnect: false });
socket.connect();
// socket.connect({ auth: { token: user.mobile_number } });

export { socket };
export const SocketContext = createContext();

here, I need to pass the user's mobile number. I cannot make any fetch requests here as they're only allowed inside components. nor can I access the UserContext here. I cannot put this (socket) code in any other component as this will make it reconnect the socket every time the component is rerendered.

Is there a way to access the user inside the socket context? or any other way by which I can do this that doesn't involve using context?


Solution

  • You wrap your SocketContext in a function component and use useContext to access other contexts within it as shown below:

    const SocketContext = createContext();
    
    const SocketProvider = ({ value, children }) => {
      const user = useContext(UserContext);
      console.log(user);
    
      return (
        <SocketContext.Provider value={value}>
          {children}
        </SocketContext.Provider>
      );
    };
    

    Usage:

      return (
        <UserContext.Provider value={user}>
          <SocketProvider value={socket}>
            <Switch>
              ... routes
            </Switch>
          </SocketProvider>
        </UserContext.Provider>
      )