Can i consume a context with another context?

123 Views Asked by At

Im trying to update a state in a function to determine is my user is logged in or not, so that later i can conditionally route the user.

I have a LoginProvider, which has a callback function that stores the user data that comes from a decoded token. Inside that function i want to update the state of my other context provider which sets to true meaning that my user is logged in.

This is my LoginContext.js:

import React, { createContext, useState, useContext } from "react";
import jwt_decode from 'jwt-decode';
import AuthContext from "./AuthContext";

const LoginContext = createContext();

export function LoginProvider({ children}) {

    const [user, setUser] = useState({}) 
    const {setIsLoggedIn} = useContext(AuthContext);

    function handleCallbackResponse(response){
        var userData = jwt_decode(response.credential); //Token with the login user Data
        setUser(userData); //Store user Data 
        setIsLoggedIn(true)
        /* console.log(userData) */
        document.getElementById('signInDiv').hidden = true;        
      }

    function handleSignOut(event) {
        setUser({}) //Empy the user Data
        
        document.getElementById('signInDiv').hidden = false;
    }  

    return(
        <LoginContext.Provider value={{user, handleCallbackResponse, handleSignOut}}>{children}</LoginContext.Provider>
    );
}

export default LoginContext

And this is my AuthContext.js:

import React, { createContext, useState } from "react";

const AuthContext = createContext()

export function AuthProvider({ children }) {
    const [isLoggedIn, setIsLoggedIn] = useState(false)

    return(
        <AuthContext.Provider value={{isLoggedIn, setIsLoggedIn}}>{children}</AuthContext.Provider>
    )
}

export default AuthContext

So in my AuthContext i have my useState hook which has destructured variables isLoggedIn and setIsLoggedIn which its initial state is false. I want to send this state with my context provider and consume it in my LoginContext.js so that there i can update the state in my callBackResponse function and set it to true. Is this possible? Im trying to do this but i have the following error.

Uncaught TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useContext(...) is undefined

This error is produced at LoginContext.js

1

There are 1 best solutions below

0
Enfield Li On

To get around, you can try to set up useEffect with user as dependency:

// put this on the top level of component tree, like <App />

export default function App() {
  const { user } = useContext(LoginContext);
  const { setIsLoggedIn } = useContext(AuthContext);

  useEffect(() => {
    if( Object.keys(user).length ) { // if user is not empty
      setIsLoggedIn(true);
    } else {
      setIsLoggedIn(false);
    }
  }, [user]) // listen to user state's change
}

This effectively makes isLoggedIn state "in sync" with user state. TBH, Object.keys(user).length is really ugly, that's because you initialized user state as empty object. If you initialize user as null, you can just do this if(user) { ... }.

BTW, since react provides us a declarative way to define UI, manipulating DOM element directly isn't really recommended, instead, you can conditionally render the signInDiv something like this:

{ Object.keys(user).length && <div id="signInDiv">my sign in div</div> }

On hindsight, you actually don't have to rely on useEffect, a better way is to move handleCallbackResponse and handleSignOut to a stand alone file (or a custom hook) and call respective setters so as to update both context state.