反应 UseContext 最新值

React UseContext latest value

我有一个用于身份验证的 React firebase 应用程序。我将 Usecontext 与 setState 一起使用。你可以看到下面的代码。当用户首次登录或注册时,此方案运行良好。但是,一旦我重新加载,上下文值就会瞬间为 null,然后它会从 firebase 的 auth 获取最新值。这导致我无法访问私有路由,即使用户已登录。

AuthContext.js 文件

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 文件

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 文件

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;

由于在重新加载时必须重新获取用户(这需要一些时间),因此用户对象将 null 直到进程完成。你可以简单地尝试 guard 你的渲染

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</>

};