React és el marc de referència per crear aplicacions dinàmiques del costat del client per a molts desenvolupadors. La naturalesa dinàmica d'aquestes aplicacions prové de la flexibilitat i la llista ampliada de capacitats i funcions que són possibles al costat del client, que va permetre als desenvolupadors crear aplicacions completes que es carreguessin al navegador en qüestió de segons, una proesa que no va ser. possible (o molt feixuc) en els temps de la web estàtica.
Amb aquesta expansió de possibilitats, va sorgir el concepte de gestió de l'estat, a mesura que la complexitat creix en les aplicacions del costat del client, la necessitat de mantenir l'estat local creix fins a convertir-se en un coll d'ampolla en si mateix si no es gestiona correctament i es concebe tenint en compte l'escalabilitat.
Aquest problema va ser abordat per molts marcs, seguint diferents enfocaments i centrant-se en diferents conjunts de subproblemes, per això és important tenir un alt nivell de comprensió de l'ecosistema del marc escollit per avaluar les necessitats de cada aplicació i emprar l'enfocament adequat seguint aquests. mètriques. Aquest article us oferirà una breu visió general dels problemes comuns de gestió de l'estat i intentarà introduir diferents enfocaments (useState, Context API) com a resposta. Tot i que aquest article presentarà múltiples solucions, només se centrarà en reptes a menor escala, tractarem temes més avançats en els propers articles.
Flux de treball d'autenticació
El codi que es mostra al llarg de l'article es pot trobar aquí.
Es pot accedir a un enllaç de previsualització en directe aquí.
Considereu el cas en què implementem el procés d'autenticació per a una aplicació React.
Com es mostra al GIF anterior, volem permetre als usuaris iniciar sessió o registrar-se a la nostra aplicació mitjançant credencials. Si es van proporcionar credencials vàlides, l'usuari s'iniciarà la sessió, l'aplicació navegarà automàticament a la pàgina d'inici i l'usuari pot procedir a utilitzar l'aplicació.
De la mateixa manera, si l'usuari tanca la sessió, els recursos de la pàgina d'inici estaran protegits després de l'inici de sessió, la pàgina d'inici de sessió serà l'única pàgina accessible per l'usuari.
Pensant en aquest flux de treball en termes d'implementació, tindríem un component principal anomenat App, el component App redirigirà l'usuari a una d'aquestes dues pàgines: Inici o Inici de sessió, l'estat actual de l'usuari (iniciat sessió, tancat la sessió) dictarà quin pàgina a la qual es redirigeix l'usuari, un canvi en l'estat actual de l'usuari (per exemple, canviar d'iniciar sessió a tancar sessió) hauria de desencadenar una redirecció instantània a la pàgina corresponent.
Com es mostra a la il·lustració anterior, volem que el component de l'aplicació tingui en compte l'estat actual i només representi una de les dues pàgines, Inici o Inici de sessió, en funció d'aquest estat actual.
Si l'usuari és nul, vol dir que no tenim cap usuari autenticat, de manera que naveguem a la pàgina d'inici de sessió automàticament i protegim la pàgina d'inici mitjançant la representació condicional. Si l'usuari existeix, fem el contrari.
Ara que tenim una comprensió sòlida del que s'ha d'implementar, explorem algunes opcions, però primer configurem el nostre projecte React,
El repositori del projecte conté una aplicació de backend de mostra que utilitzarem per implementar el costat de la interfície (no hi entrarem, ja que no és el focus principal aquí, però el codi es va mantenir senzill intencionadament, de manera que no tindreu problemes amb ell). )
Comencem creant les pàgines i components següents:
-
Pàgina d'inici
-
Pàgina d'inici de sessió
-
Edita la pàgina d'usuari
-
Component de la barra de navegació
-
Component UserDropdown
Una aplicació React amb diverses pàgines necessita una navegació adequada, per això podem utilitzar react-router-dom per crear un context global d'encaminador del navegador i registrar diferents rutes de React.
yarn add react-router-dom
Sabem que molts lectors prefereixen seguir tutorials, així que aquí teniu la plantilla inicial per posar-vos al dia. Aquesta branca d'inici utilitza DaisyUI per a components TailwindCSS JSX predefinits. Inclou tots els components, pàgines i l'encaminador ja configurat. Si esteu pensant en seguir aquest tutorial, crear tot el flux d'autenticació per vosaltres mateixos seguint passos senzills, comenceu per bifurcar primer el dipòsit. Després de bifurcar el dipòsit, cloneu-lo i comenceu des de la branca start-herebranca:
git clone git@github.com:<your-username>/fullstack-resourcify.git
Un cop estireu la branca d'inici-aquí:
-
Obriu el projecte amb el vostre editor de codi preferit
-
Canvia el directori a frontend/
-
Instal·lar dependències: fil
-
Inicieu un servidor de desenvolupament: yarn dev·
La vista prèvia hauria de semblar a això:
El nom representat a la barra de navegació, a la part superior dreta, és una variable d'estat definida al component principal de l'aplicació. La mateixa variable es passa tant a la barra de navegació com a la pàgina d'inici. El formulari senzill utilitzat anteriorment actualitza la variable d'estat "nom" del component EditPage.
Els dos enfocaments que es presenten a continuació entraran en els detalls de la implementació:
Primer enfocament: useState
useState()
useState és un dels ganxos de React més utilitzats, us permet crear i mutar estat en un component React Functional. El component useState té una implementació molt senzilla i és fàcil d'utilitzar: per crear un nou estat, cal cridar a useState amb el valor inicial del vostre estat i el ganxo useState retornarà una matriu que conté dues variables: la primera és l'estat. variable que podeu utilitzar per fer referència al vostre estat, i la segona una funció que utilitzeu per canviar el valor de l'estat: bastant senzill.
Què tal si ho veiem en acció? El nom representat a la barra de navegació, a la part superior dreta, és una variable d'estat definida al component principal de l'aplicació. La mateixa variable es passa tant a la barra de navegació com a la pàgina d'inici. El formulari senzill utilitzat anteriorment actualitza la variable d'estat "nom" del component EditPage. La conclusió és la següent: useState és un ganxo principal que accepta un estat inicial com a paràmetre i retorna dues variables que contenen dos valors, la variable d'estat que conté l'estat inicial i una funció de configuració per a la mateixa variable d'estat.
Desglossem-ho i veiem com es va implementar en primer lloc.
- Creació de la variable d'estat "nom":
./src/App.jsx
import { useState } from "react";
function App() {
const testValue = "CLA";
//using the useState hook to create a state variable out of an initial value passed as an argument
const [name, setName] = useState(testValue);
console.log(`Rendering: ${name}`);
return (...)};
Atrezzo
Els accessoris són un dels components bàsics d'un component de reacció, conceptualment, si penseu en un component funcional de React com una funció Javascript, els accessoris no són més que els paràmetres de la funció, la combinació d'accessoris i el ganxo useState us pot oferir un marc sòlid. per gestionar l'estat mitjançant una senzilla aplicació React.
Els accessoris de React es passen com a atributs a components personalitzats. Els atributs passats com a accessoris es poden desestructurar de l'objecte props en acceptar-lo com a argument, de manera similar a això:
Atrezzo passant
<Routes>
<Route path="/" element={<Home name={name} />} /> // Passing name as a prop to
Home Component
<Route
path="/user"
element={<EditUser name={name} setName={setName} />} // passing both name and setItem function as props to EditUser component
/>
<Route path="/login" element={<Login />} />
</Routes>
Els accessoris es poden acceptar i utilitzar dins d'un component funcional similar als arguments de funció normals. És perquè "nom" es passa com a complement al component Inici, que podem representar-lo al mateix component. A l'exemple següent, estem acceptant l'accessori passat mitjançant la sintaxi de desestructuració per extreure la propietat name de l'objecte props.
Acceptant accessoris
./src/pages/Home.jsx
... ...
export default function Home({name}) { //Destructuring the name property from the props object, another approach would be: Home(props.name)
console.log("Rendering: Home");
return (
<div className="flex flex-col bg-white m-auto p-auto">
<h1 className="flex py-5 lg:px-20 md:px-10 mx-5 font-bold text-2xl text-gray-800">
Welcome {name}
</h1>
... ...
Consell professional
Obriu la consola del navegador i observeu com es tornen a representar tots els components que utilitzen l'element "nom" quan l'estat canvia. Quan manipuleu una variable d'estat, React emmagatzemarà l'estat següent, tornarà a representar el vostre component amb els nous valors i actualitzarà la interfície d'usuari.
useState Inconvenients
Atrezzo-perforació
La perforació d'accessoris és un terme per referir-se a una jerarquia de components on un conjunt de components necessita certs accessoris proporcionats per un component principal, una solució alternativa que solen utilitzar els desenvolupadors sense experiència és passar aquests accessoris per tota la cadena de components, el problema amb aquest L'enfocament és que un canvi en qualsevol d'aquests accessoris provocarà que tota la cadena de components es torni a renderitzar, alentint efectivament tota l'aplicació com a resultat d'aquests renders innecessaris, els components del mig de la cadena que no requereixen aquests accessoris. actuar com a mitjà per transferir accessoris.
Exemple:
-
Es va definir una variable d'estat al component principal de l'aplicació mitjançant el ganxo useState().
-
S'ha passat un nom de suport al component Navbar
-
El mateix objecte acceptat a la barra de navegació i passat com a objecte una vegada més al component UserDropdown
-
UserDropdown és l'últim element fill que accepta la prop.
./src/App.jsx
... ...
function App() {
const [name, setName] = useState(test);
console.log("Rendering: App");
return (
<BrowserRouter>
<div className="h-screen">
<Navbar name={name} />
<main className="px-4">
... ...
./src/components/Navbar.jsx
import React from "react";
import Logo from "../assets/cla.svg";
import { BiSearchAlt } from "react-icons/bi";
import { Link } from "react-router-dom";
import UserDropdown from "./UserDropdown";
export default function Navbar({ name }) {
console.log("Rendering: Navbar");
return (
<>
<div className="navbar bg-base-100 drop-shadow-sm">
<div className="flex-1">
<Link
to="/"
className="btn btn-ghost normal-case text-md md:text-xl px-2 gap-1"
>
<img src={Logo} className="h-6" alt="" />
Resources
</Link>
</div>
<UserDropdown name={name} />
</div>
</>
);
}
Imagineu el difícil que és mantenir una aplicació React amb diferents capes de components que passen i representen el mateix estat.
Complexitat creixent i qualitat del codi
Amb l'ús d'useState i d'accessoris com a únic mitjà de gestió de l'estat en una aplicació de reacció, la base de codi pot créixer ràpidament en complexitat, havent de gestionar desenes o centenars de variables d'estat, que poden ser duplicades les unes de les altres, disperses en diferents fitxers i Els components poden ser bastant descoratjadors, qualsevol canvi a una variable d'estat determinada requerirà una consideració acurada de les dependències entre components per evitar qualsevol possible reproducció addicional en una aplicació ja lenta.
Segon enfocament: API de context
L'API de context és l'intent de React de resoldre els inconvenients d'utilitzar només accessoris i useState per a la gestió de l'estat, en particular, l'API de context és una resposta al problema esmentat anteriorment sobre la necessitat de transmetre accessoris a tot l'arbre de components. Amb l'ús del context, podeu definir un estat per a les dades que considereu globals i accedir al seu estat des de qualsevol punt de l'arbre de components: no hi ha més perforació.
És important assenyalar que l'API de context es va concebre inicialment per resoldre el problema de l'intercanvi global de dades, dades com ara els temes de la interfície d'usuari, la informació d'autenticació que és el nostre cas d'ús, els idiomes, etc.), per a altres tipus de dades que cal compartir. entre més d'un component, però no és necessàriament global per a tota l'aplicació, pot ser que el context no sigui la millor opció, depenent del cas d'ús, podeu considerar altres tècniques com ara composició de components. /composition-vs-inheritance.html) que queda fora de l'abast d'aquest article.
Canviant a context
Creació del context d'autenticació
createContext és senzill, crea una nova variable de context, pren un únic paràmetre opcional: el valor per defecte de la variable de context.
Vegem-ho en acció, primer creeu una nova carpeta "contexts" i un nou fitxer dins d'ella "Auth.jsx". Per crear un context nou, hem d'invocar la funció createContext(), assignar el valor retornat a una nova variable Auth que s'exportarà a continuació:
./src/contexts/Auth.jsx
import { createContext } from "react";
export const Auth = createContext();
Proporcioneu el context d'autenticació
Ara hem d'exposar la variable de context "Auth" que hem creat anteriorment, per aconseguir-ho utilitzem el proveïdor de context, el proveïdor de context és un component que té un suport "valor", podem utilitzar aquest suport per compartir un valor: nom – a través de l'arbre de components, en embolicar l'arbre de components amb el component del proveïdor fem que aquest valor sigui accessible des de qualsevol lloc dins de l'arbre de components, sense necessitat de transmetre aquest suport a cada component secundari individualment.
En el nostre exemple d'autenticació, necessitem una variable per contenir l'objecte d'usuari i algun tipus de setter per manipular aquesta variable d'estat, aquest és un cas d'ús perfecte per a useState. Quan utilitzeu Context, heu d'assegurar-vos que esteu definint les dades que voleu proporcionar i que esteu passant aquestes dades (usuari en el nostre exemple) a tot l'arbre de components imbricat dins, així que definiu un nou usuari de variable d'estat dins del component del proveïdor i finalment passem user i setUser dins d'una matriu com el valor que el proveïdor exposarà a l'arbre de components:
./src/contexts/Auth.jsx
import { createContext, useState } from "react";
export const Auth = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
return <Auth.Provider value={[user, setUser]}>{children}</Auth.Provider>;
};
Una altra cosa que podem fer és moure la nostra variable d'estat "nom" del component principal de l'aplicació al context Auth i exposar-la als components imbricats:
import { createContext, useState } from "react";
export const Auth = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [name, setName] = useState("CLA");
return <Auth.Provider value={[name, setName]}>{children}</Auth.Provider>;
};
Ara tot el que queda és niar la nostra aplicació al mateix component AuthProvider que acabem d'exportar.
./src/main.jsx:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { AuthProvider } from "./contexts/Auth";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")).render(
<AuthProvider>
<App />
</AuthProvider>
);
Com que estem renderitzant l'element secundari dins d'Auth.Provider, tots els elements que estan imbricats dins del component AuthProvider ara poden consumir el valor de prop que hem passat a Auth.Provider. Pot semblar confús, però un cop ho experimenteu, proveu de proporcionar i consumir un estat global - Context. Després de tot, només tenia sentit per a mi després d'experimentar amb l'API de context.
Consumir el context d'autenticació
El pas final és senzill, utilitzem el ganxo de context "useContext" per accedir al valor que proporciona el proveïdor de context de "Auth", que en el nostre cas és la matriu que conté user i setUser, en el codi següent, podem utilitzeu useContext per consumir el context Auth dins de la barra de navegació. Això només és possible perquè la barra de navegació està imbricada dins del component de l'aplicació i, com que AuthProvider envolta el component de l'aplicació, la prop de valor només es pot consumir utilitzant el ganxo useContext. Una altra eina fantàstica que proporciona React de manera immediata per gestionar qualsevol dada a la qual es pugui accedir globalment i també manipulada per qualsevol component del consumidor.
./src/components/Navbar.jsx
export default function Navbar() {
const [name, setName] = useContext(Auth);
console.log(name)
return (...)};
Observeu com ja no acceptem cap accessori al component funcional Navbar(). Estem utilitzant useContext(Auth) per consumir el context Auth, agafant tant el nom com el setName. Això també vol dir que ja no necessitem passar el suport a Navbar:
./src/App.jsx
// ... //
return (
<BrowserRouter>
<div className="h-screen">
<Navbar/> // no need to pass prop anymore
// ... //
Actualització del context d'autenticació
També podem utilitzar la funció setName proporcionada per manipular la variable d'estat "nom":
./src/pages/EditUser.jsx
export default function EditUser() { // no need to accept props anymore
const [name, setName] = useContext(Auth); // grabbing the name and setName variables from Auth context
console.log("Rendering: EditUser");
Presentació del ganxo useReducer().
A l'exemple anterior vam utilitzar l'API de context per gestionar i compartir el nostre estat a l'arbre de components, potser haureu notat que encara estem utilitzant useState com a base de la nostra lògica, i això està molt bé ja que el nostre estat encara és un objecte simple. en aquest punt, però si haguéssim d'ampliar les capacitats del nostre flux d'autenticació, sens dubte haurem d'emmagatzemar més que només el correu electrònic de l'usuari que ha iniciat sessió actualment, i aquí és on tornarem a les limitacions a les quals vam entrar anteriorment pel que fa a l'ús d'useState amb estat complex, afortunadament, React resol aquest problema proporcionant una alternativa a useState per gestionar l'estat complex: introduïu useReducer.
useReducer es pot pensar com una versió generalitzada d'useState, pren dos paràmetres: una funció reductora i un estat inicial.
Res interessant a destacar per a l'estat inicial, la màgia passa dins de la funció reductora: comprova el tipus d'acció que s'ha produït i, depenent d'aquesta acció, el reductor determinarà quines actualitzacions s'ha d'aplicar a l'estat i retornarà el seu nou valor. .
Mirant el codi següent, la funció reductora té dos tipus d'accions possibles:
-
"LOGIN": en aquest cas, l'estat de l'usuari s'actualitzarà amb les noves credencials d'usuari proporcionades a la càrrega útil de l'acció.
-
"LOGOUT": en aquest cas, l'estat de l'usuari s'eliminarà de l'emmagatzematge local i es tornarà a nul.
És important tenir en compte que l'objecte d'acció conté un camp de tipus que determina quina lògica s'ha d'aplicar i un camp de càrrega útil opcional per proporcionar les dades necessàries per aplicar aquesta lògica.
Finalment, el ganxo useReducer retorna l'estat actual i una funció d'enviament que fem servir per passar una acció al reductor.
Per a la resta de la lògica, és idèntic a l'exemple anterior:
./src/contexts/Auth.jsx
import { createContext, useEffect, useReducer, useState } from "react";
export const Auth = createContext();
import { createContext, useReducer } from "react";
export const Auth = createContext();
const reducer = (state, action) => {
switch (action.type) {
case "LOGIN":
return { user: action.payload };
case "LOGOUT":
localStorage.removeItem("user");
return { user: null };
default:
break;
}
};
export const AuthProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, {
user: null,
});
return (
<Auth.Provider value={{ ...state, dispatch }}>{children}</Auth.Provider>
);
};
Enviament d'accions en comptes d'utilitzar la funció de configuració setState - per exemple: setName -
Com acabem d'esmentar, utilitzem la funció d'enviament per passar una acció al reductor, en el codi següent, iniciem una acció LOGIN i proporcionem el correu electrònic de l'usuari com a càrrega útil, ara l'estat de l'usuari s'actualitzarà i aquest canvi es desencadenarà una restitució de tots els components subscrits a l'estat d'usuari. És important assenyalar que només s'activarà un re-rendering si es produeix un canvi real d'estat, no es tornarà a renderitzar si el reductor retorna el mateix estat anterior.
export default function Login() {
const { dispatch } = useContext(Auth);
const handleLogin = async (e) => {
// Updating the global Auth context
dispatch({ type: "LOGIN", payload: {email: email.current.value} });
};
return (...)};
Inici de sessió d'usuari
Consell professional
Observeu com l'objecte d'usuari que rebem després d'un inici de sessió satisfactori s'emmagatzema ara al localStorage.
Ganxo personalitzat per iniciar sessió
Ara que tenim un bon control sobre useReducer, podem encapsular encara més la nostra lògica d'inici de sessió i tancament de sessió en els seus propis ganxos personalitzats separats, mitjançant una única trucada al ganxo d'inici de sessió, podem gestionar una trucada d'API a la ruta d'inici de sessió, recuperar el nou usuari. credencials i emmagatzemar-les a l'emmagatzematge local, envia una trucada LOGIN per actualitzar l'estat de l'usuari, tot mentre s'ocupa de la gestió d'errors:
./src/hooks/useLogin.jsx
import { useContext, useState } from "react";
import { Auth } from "../contexts/Auth";
export const useLogin = () => {
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const { dispatch } = useContext(Auth);
const login = async (email, password) => {
setIsLoading(true);
setError(null);
try {
const response = await fetch("/api/users/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
const json = await response.json();
if (json.name === "Error") {
setError(json.message);
setIsLoading(false);
}
if (!response.ok) {
setIsLoading(false);
setError(json);
}
if (response.ok) {
// Save the user and token in the localstorage
localStorage.setItem("user", JSON.stringify(json));
// Updating the global Auth context
dispatch({ type: "LOGIN", payload: json });
setIsLoading(false);
}
} catch (error) {
console.log(error);
}
};
return { error, isLoading, login };
};
Nota: per als usuaris de React més avançats entre els lectors, potser us preguntareu per què no hem utilitzat la funció d'inicialització mandrosa d'useReducer per recuperar les credencials de l'usuari, useReducer accepta un tercer paràmetre opcional anomenat funció d'inici, aquesta funció s'utilitza en cas que hem d'aplicar una mica de lògica abans de poder obtenir el valor inicial de l'estat, el motiu pel qual no vam optar per això és una simple qüestió de separació de preocupacions, el codi d'aquesta manera és més senzill d'entendre i, per tant, més senzill de mantenir .
Pàgina d'inici de sessió
Així és com es veu la part superior de la nostra pàgina d'inici de sessió després d'utilitzar el ganxo useLogin() per extreure la funció d'inici de sessió i invocar la funció d'inici de sessió amb les credencials enviades per un usuari:
// ... ... //
export default function Login() {
const { login, isLoading, error } = useLogin();
console.log("Rendering: Login");
const email = createRef(null);
const password = createRef(null);
const handleLogin = async (e) => {
await login(email.current.value, password.current.value);
};
return (...)
// ... ... //
També estem desactivant la funció Envia quan l'usuari envia el formulari:
<button
onClick={handleLogin}
disabled={isLoading}
className="btn btn-square w-full bg-gray-100 text-gray-600 hover:bg-gray-300 border-none"
>
{isLoading && "A moment please!"}
{!isLoading && "Login"}
</button>
I mostrant qualsevol error d'autenticació que rebem del nostre backend:
{
error && <span className="text-red-500 p-2">{error.message}</span>;
}
Manteniment de l'estat d'usuari
Potser us preguntareu per què hem d'emmagatzemar l'objecte d'usuari al localStorage, en poques paraules, volem mantenir l'usuari connectat mentre el testimoni no caduqui. L'ús de localStorage és una manera fantàstica d'emmagatzemar fragments de JSON, com en el nostre exemple. Observeu com s'esborra l'estat si actualitzeu la pàgina després d'iniciar sessió. Això es pot resoldre fàcilment mitjançant un ganxo useEffect per comprovar si tenim un objecte d'usuari emmagatzemat a localStorage, si n'hi ha, iniciem la sessió a l'usuari automàticament:
// ... ... //
export const AuthProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, {
user: null,
});
useEffect(() => {
const user = JSON.parse(localStorage.getItem("user"));
if (user) {
return dispatch({ type: "LOGIN", payload: user });
}
}, []);
return (
<Auth.Provider value={{ ...state, dispatch }}>{children}</Auth.Provider>
);
};
Ganxos personalitzats per tancar la sessió
El mateix s'aplica amb el ganxo de tancament de sessió, aquí estem enviant una acció de tancament de sessió per eliminar les credencials d'usuari actuals tant de l'estat com de l'emmagatzematge local:
./src/hooks/useLogout.jsx
import { useContext } from "react";
import { Auth } from "../contexts/Auth";
export const useLogout = () => {
const { dispatch } = useContext(Auth);
const logout = () => {
// delete user from the localstorage
localStorage.removeItem("user");
// Wipe out the Auth context (user:null) / dipatch 'LOGOUT'
dispatch({ type: "LOGOUT" });
};
return { logout };
};
Tancament de sessió de l'usuari
Per tancar la sessió d'un usuari, afegim un esdeveniment de clic al botó Tancar sessió que es troba a UserDropdown.jsx i gestionar-lo en conseqüència:
./src/components/UserDropdown.jsx
// Extracting the logout function from useLogout() and handling the click event listener //
export default function UserDropdown() {
const { user } = useContext(Auth);
const { logout } = useLogout();
console.log("Rendering: UserDropdown");
const handleLogout = () => {
logout();
};
// ... ... //
// Adding a click event listener to logout button //
<li>
<button onClick={handleLogout}>Logout</button>
</li>
// ... ... //
Protecció de les rutes de React
El pas final per implementar la nostra aplicació és aprofitar l'estat global de l'usuari per controlar la navegació de l'usuari, un recordatori ràpid sobre quin comportament hem d'aconseguir: inicialment l'usuari és rebut per la pàgina d'inici de sessió, a partir d'aquest moment l'usuari només pot accedir a la pàgina d'inici. després d'un inici de sessió satisfactori, de la mateixa manera, l'usuari serà redirigit a la pàgina d'inici de sessió quan tanqui la sessió.
Ho aconseguim amb l'ajuda de la biblioteca react-router-dom definint 2 rutes: "/" i "/login", controlem quin component es renderitzarà a cada ruta mitjançant l'estat d'autenticació global., l'avaluació d'auth a null representa un usuari no autenticat i viceversa:
./src/App.jsx
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
import "./App.css";
import Navbar from "./components/Navbar";
import Home from "./pages/Home";
import Login from "./pages/Login";
import { useContext } from "react";
import { Auth } from "./contexts/Auth";
function App() {
const { user } = useContext(Auth);
return (
<BrowserRouter>
<div className="h-screen">
<Navbar />
<main className="px-4">
<Routes>
<Route
path="/"
element={user ? <Home /> : <Navigate to="/login" />}
/>
<Route
path="/login"
element={!user ? <Login /> : <Navigate to="/" />}
/>
</Routes>
</main>
</div>
</BrowserRouter>
);
}
export default App;
Diagrama de resum
Conclusió
En aquest article hem intentat abordar el cas d'ús senzill però molt comú d'implementar la gestió de l'estat per a un flux de treball d'autenticació, repassant els diferents enfocaments, la justificació de cadascun i els seus compromisos. La gestió de l'estat en marcs del costat del client i en particular a React és un dels temes que més es parla a la comunitat de frontend, simplement perquè pot augmentar o trencar el rendiment i l'escalabilitat de la vostra aplicació. La gran quantitat de les diferents tècniques, patrons, biblioteques i eines que intenten resoldre aquest problema de la gestió estatal és aclaparadora, el nostre objectiu era donar-vos una comprensió sòlida de les pràctiques perquè pugueu implementar-les en la vostra pròpia aplicació, per a una aplicació més avançada. tècniques i patrons de gestió de l'estat en aplicacions més complexes, consulteu el nostre següent article on entrem en redux per a la gestió de l'estat escalable a React.
Aviat
ContextAPI vs Redux Toolkit
Redux va tenir molts anys d'adopció a la comunitat abans del conjunt d'eines Redux, de fet, RTK es va introduir com a plantilla inicial per iniciar la gestió de l'estat de redux en aplicacions noves (el seu nom inicial era "redux-starter-kit" l'octubre de 2019), tot i que avui dia, hi ha un consens general entre els mantenedors de Redux i la comunitat que el kit d'eines de Redux és la manera vàlida de treballar amb redux.RTX resumeix una gran part de la lògica de Redux que fa que sigui més fàcil d'utilitzar, amb molt menys detalls, i anima els desenvolupadors a seguiu les millors pràctiques, una diferència principal entre les dues és que Redux es va crear per no tenir opinions, proporcionant una API mínima i esperant que els desenvolupadors facin la major part del treball pesat escrivint les seves pròpies biblioteques per a tasques comunes i tractant l'estructura del codi. això va provocar un temps de desenvolupament lent i un codi desordenat, el kit d'eines Redux es va afegir com una capa addicional d'abstracció que evita que els desenvolupadors caiguin en els seus inconvenients comuns, consulteu la documentació oficial per obtenir més informació i el raonament dels seus mantenedors aquí.