Cet extrait de code est tout ce dont vous avez besoin pour gérer l'état d'authentification sur votre application React. Il utilise l'API Context pour gérer l'état des utilisateurs dans l'application.
plus de babillage, plongeons-nous simplement dans le vif du sujet.
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>; };
Nous commençons par importer les hooks React nécessaires et un hook useLocalStorage personnalisé. Ensuite, nous définissons les types TypeScript pour notre système d'authentification, notamment SignInForm, User, AuthState et 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; };
Ici, nous créons le AuthDataContext et un hook useAuth personnalisé. Ce hook garantit que nous utilisons le contexte au sein d'un fournisseur et fournit un moyen pratique d'accéder à notre état d'authentification.
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> ); };
Le composant AuthProvider est le cœur de notre système d'authentification. Il utilise le hook useLocalStorage pour conserver l'état de l'utilisateur et fournit la valeur de contexte à ses enfants.
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; } };
Cette fonction vérifie si le JWT a expiré et enregistre le temps restant s'il est toujours valide.
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"; } };
La fonction signOut envoie une requête POST au point de terminaison de déconnexion et efface l'état de l'utilisateur.
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 }); } };
La fonction de connexion envoie les informations d'identification de l'utilisateur au point de terminaison de connexion et met à jour l'état de l'utilisateur avec les données de réponse.
useEffect(() => { if (!user) return; if (isJwtExpired(user.exp)) signOut(); }, [user]);
Cet effet s'exécute chaque fois que l'état de l'utilisateur change, vérifiant si le JWT a expiré et se déconnectant si nécessaire.
Voici un exemple d'implémentation du hook useLocalStorage d'ailleurs
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]; }
et tu as fini ? facile à presser au citron. assurez-vous de modifier la logique de récupération pour votre propre structure API si nécessaire.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!