此程式碼片段是您在 React 應用程式上管理身分驗證狀態所需的全部內容,使用 Context API 來管理整個應用程式的使用者狀態。
廢話不多說,我們進入正題吧。
import { createContext, Dispatch, ReactNode, SetStateAction, useContext, useEffect } from "react"; import { useLocalStorage } from "../utils/useLocalStorage"; type SignInForm = { email: string; password: string; }; type User = { id: number; email: string; }; type AuthState = User & { exp: number }; type UserContextType = { user: User | null; setUser: Dispatch<SetStateAction<AuthState | null>>; signOut: () => Promise<string | undefined>; signIn: (signInForm: SignInForm) => Promise<string | undefined>; };
我們先匯入必要的 React hook 和自訂 useLocalStorage hook。然後,我們為我們的驗證系統定義 TypeScript 類型,包括 SignInForm、User、AuthState 和 UserContextType。
const AuthDataContext = createContext<UserContextType | undefined>(undefined); export const useAuth = (): UserContextType => { const context = useContext(AuthDataContext); if (!context) { throw new Error("useAuth must be used within a UserDataProvider"); } return context; };
在這裡,我們建立 AuthDataContext 和自訂 useAuth 掛鉤。這個鉤子確保我們使用提供者中的上下文,並提供一種方便的方法來存取我們的身份驗證狀態。
export const AuthProvider = ({ children }: { children: ReactNode }) => { const [user, setUser] = useLocalStorage<AuthState | null>("user", null); // ... (other functions) return ( <AuthDataContext.Provider value={{ user, setUser, signIn, signOut }}> {children} </AuthDataContext.Provider> ); };
AuthProvider 元件是我們認證系統的核心。它使用 useLocalStorage 掛鉤來保存使用者狀態並為其子級提供上下文值。
const isJwtExpired = (unixTime: number) => { const currentTime = Math.floor(Date.now() / 1000); const timeRemaining = unixTime - currentTime; if (timeRemaining <= 0) { console.log("The JWT is expired."); setUser(null); return true; } else { const hours = Math.floor(timeRemaining / 3600); const minutes = Math.floor((timeRemaining % 3600) / 60); console.log(`Time remaining before JWT expires: ${hours} hours ${minutes} minutes`); return false; } };
此函數檢查 JWT 是否已過期,並記錄剩餘時間(如果仍然有效)。
const signOut = async () => { const res = await fetch("http://localhost:8080/auth/signout", { method: "POST" }); setUser(null); if (!res.ok) { console.log("Error signing out"); return (await res.text()) || "Something went wrong"; } };
signOut 函數向登出端點發出 POST 請求並清除使用者狀態。
const signIn = async (signInForm: SignInForm) => { const res = await fetch("http://localhost:8080/auth/signin", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(signInForm), }); if (!res.ok) { return (await res.text()) || "Something went wrong"; } const data = (await res.json()) as { user: User; exp: number }; if (data) { setUser({ ...data.user, exp: data.exp }); } };
signIn 函數將使用者的憑證傳送到登入端點,並使用回應資料更新使用者狀態。
useEffect(() => { if (!user) return; if (isJwtExpired(user.exp)) signOut(); }, [user]);
只要使用者狀態發生變化,就會執行此效果,檢查 JWT 是否已過期,並在必要時登出。
這是 useLocalStorage 掛鉤的範例實作
import { useState, useEffect, Dispatch, SetStateAction } from "react"; export function useLocalStorage<T>( key: string, initialValue: T ): [T, Dispatch<SetStateAction<T>>] { const [storedValue, setStoredValue] = useState<T>(() => { try { const item = localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.log(error); return initialValue; } }); const setValue: Dispatch<SetStateAction<T>> = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.log(error); } }; useEffect(() => { const handleStorageChange = (event: StorageEvent) => { if (event.key === key) { setStoredValue(JSON.parse(event.newValue || "null")); } }; window.addEventListener("storage", handleStorageChange); return () => window.removeEventListener("storage", handleStorageChange); }, [key]); return [storedValue, setValue]; }
你完成了嗎?簡單的檸檬榨汁..如果需要,請確保修改您自己的 api 結構的獲取邏輯。
以上是使用 useContext API 管理 React 中的身份驗證狀態的詳細內容。更多資訊請關注PHP中文網其他相關文章!