Home > Blockchain >  React UseContext latest value
React UseContext latest value

Time:11-07

I have a react firebase Application for authentication. I am using Usecontext along with the setState. You can see the code below. This scenario works fine when user logs in for the first time or signs up. But as soon as I reload, the context value is null for a split second and then it gets the latest value from the auth of firebase. This is causing a problem for me to access the private route even though the user is logged in.

AuthContext.js File

import React, { useContext, useEffect, useState } from "react";
import { firebaseAuth } from "../firebase";
import {
  createUserWithEmailAndPassword,
  signOut,
  signInWithEmailAndPassword,
  onAuthStateChanged,
} from "firebase/auth";

const AuthContext = React.createContext();

export const useAuth = () => {
  return useContext(AuthContext);
};

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  console.log("Auth Context User:", user);

  useEffect(() => {
    const unsub = onAuthStateChanged(firebaseAuth, (user) => {
      setUser(user);
    });
    return unsub();
  }, [user]);

  function SignUp(email, password) {
    return createUserWithEmailAndPassword(firebaseAuth, email, password);
  }

  function Logout() {
    return signOut(firebaseAuth);
  }

  function Login(email, password) {
    return signInWithEmailAndPassword(firebaseAuth, email, password);
  }

  const value = {
    logout: Logout,
    signup: SignUp,
    login: Login,
    user,
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

App.js File

import Header from "./components/Header";
import Login from "./components/Login";
import NotFound from "./components/NotFound";
import Signup from "./components/Signup";
import Home from "./components/Home";
import AuthGuard from "./guard/AuthGuard";
import ErrorComp from "./components/ErrorComp";

import { AuthContextProvider } from "./context/AuthContext";

import { GlobalStyles } from "./styledComps/Global";
import { Route, Routes } from "react-router-dom";

function App() {
  return (
    <>
      <GlobalStyles />
      <AuthContextProvider>
        <Header />
        <ErrorComp>
          <Routes>
            <Route path="" element={<Login />} exact />
            <Route path="/signup" element={<Signup />} />
            <Route
              path="/home"
              element={
                <AuthGuard>
                  <Home />
                </AuthGuard>
              }
            />
            <Route path="*" element={<NotFound />} />
          </Routes>
        </ErrorComp>
      </AuthContextProvider>
    </>
  );
}

export default App;

AuthGuard.js File

import React from "react";
import { Navigate, useLocation } from "react-router-dom";
import { useAuth } from "../context/AuthContext";

const AuthGuard = ({ children }) => {
  let { user } = useAuth();
  let location = useLocation();

  console.log("user", user);

  if (!user) {
    return <Navigate to="/" state={{ from: location }} />;
  }

  return children;
};

export default AuthGuard;

CodePudding user response:

Since the user has to get refetched when you reload (which takes some time), the user object will be null until the process has finished. You could simply try to just guard your rendering by

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  console.log("Auth Context User:", user);

  useEffect(() => {
    const unsub = onAuthStateChanged(firebaseAuth, (user) => {
      setUser(user);
    });
    return unsub();
  }, [user]);

  function SignUp(email, password) {
    return createUserWithEmailAndPassword(firebaseAuth, email, password);
  }

  function Logout() {
    return signOut(firebaseAuth);
  }

  function Login(email, password) {
    return signInWithEmailAndPassword(firebaseAuth, email, password);
  }

  const value = {
    logout: Logout,
    signup: SignUp,
    login: Login,
    user,
  };

  if ( user !== null ) {
    return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
  }

  return <>Loading ... or render eg. a spinner</>

};
  • Related