State Management in React: Praktický príklad

reagovať
riadenie stavu
kontext api
State Management in React: Praktický príklad cover image

React je základom pre vytváranie dynamických aplikácií na strane klienta pre mnohých vývojárov. Dynamická povaha týchto aplikácií pochádza z flexibility a rozšíreného zoznamu možností a funkcií, ktoré sú možné na strane klienta, čo vývojárom umožnilo vytvoriť plnohodnotné aplikácie, ktoré sa načítajú do prehliadača v priebehu niekoľkých sekúnd, čo je výkon, ktorý nebol možný. možné (alebo veľmi ťažkopádne) v časoch statického webu.

S týmto rozšírením možností prišiel koncept riadenia stavu, keďže zložitosť aplikácií na strane klienta narastá, potreba udržiavať lokálny stav sa stáva prekážkou, ak nie je správne spracované a koncipované s ohľadom na škálovateľnosť.

Tento problém bol riešený mnohými rámcami, ktoré sledovali rôzne prístupy a sústreďovali sa na rôzne súbory čiastkových problémov, preto je dôležité mať vysokú úroveň porozumenia ekosystému rámca výberu, aby ste mohli posúdiť potreby každej aplikácie a použiť správny prístup podľa týchto metriky. Tento článok vám poskytne stručný prehľad bežných problémov riadenia štátu a pokúsi sa predstaviť rôzne prístupy (useState, Context API) ako odpoveď naň. Aj keď tento článok predstaví viacero riešení, zameria sa len na výzvy v menšom rozsahu, v nadchádzajúcich článkoch sa budeme venovať pokročilejším témam.

Pracovný postup overovania

Kód uvedený v celom článku nájdete tu.

Odkaz na živú ukážku je dostupný tu.

Zvážte prípad, keď implementujeme proces autentifikácie pre aplikáciu React.

User Login

Ako je znázornené na obrázku GIF vyššie, chceme používateľom umožniť prihlásiť sa alebo zaregistrovať sa do našej aplikácie pomocou poverení. Ak boli poskytnuté platné prihlasovacie údaje, používateľ bude prihlásený, aplikácia automaticky prejde na domovskú stránku a používateľ môže pokračovať v používaní aplikácie.

Podobne, ak sa používateľ odhlási, zdroje domovskej stránky budú chránené aj po prihlásení, prihlasovacia stránka bude jedinou stránkou prístupnou používateľovi.

Ak uvažujeme o tomto pracovnom postupe z hľadiska implementácie, mali by sme hlavný komponent s názvom App, komponent App presmeruje používateľa na jednu z dvoch stránok: Domov alebo Prihlásenie, aktuálny stav používateľa (prihlásený, odhlásený) bude určovať, ktorá stránku, na ktorú je používateľ presmerovaný, zmena aktuálneho stavu používateľa (napríklad zmena z prihláseného na odhláseného) by mala spustiť okamžité presmerovanie na príslušnú stránku.

State

Ako je znázornené na obrázku vyššie, chceme, aby komponent aplikácie zohľadnil aktuálny stav a vykreslil iba jednu z dvoch stránok – Domov alebo Prihlásenie – na základe tohto aktuálneho stavu.

Ak je používateľ nulový, znamená to, že nemáme žiadneho overeného používateľa, takže automaticky prejdeme na prihlasovaciu stránku a chránime domovskú stránku pomocou podmieneného vykresľovania. Ak používateľ existuje, robíme opak.

Teraz, keď dobre rozumieme tomu, čo by sa malo implementovať, poďme preskúmať niekoľko možností, ale najprv nastavme náš projekt React,

Projektové úložisko obsahuje vzorovú backendovú aplikáciu, ktorú použijeme na implementáciu frontendovej strany (nebudeme sa tomu venovať, pretože to tu nie je hlavné, ale kód bol zámerne jednoduchý, takže s tým nebudete mať problémy )

Začneme vytvorením nasledujúcich stránok a komponentov:

  • Domovská stránka

  • Prihlasovacia stránka

  • Upraviť stránku používateľa

  • Komponent navigačnej lišty

  • Komponent UserDropdown

Aplikácia React s viacerými stránkami potrebuje správnu navigáciu, na to môžeme použiť reakciu-router-dom na vytvorenie globálneho kontextu smerovača prehliadača a registráciu rôznych ciest React.


yarn add react-router-dom

Vieme, že mnohí čitatelia uprednostňujú sledovanie spolu s návodmi, takže tu je úvodná šablóna, ktorá vám pomôže rýchlo. Táto úvodná vetva používa DaisyUI pre preddefinované komponenty TailwindCSS JSX. Zahŕňa všetky komponenty, stránky a už nastavený smerovač. Ak uvažujete o tom, že budete postupovať podľa tohto návodu a vytvoríte si celý autorizačný tok podľa jednoduchých krokov, začnite najskôr rozvetvením úložiska. Po rozvetvení úložiska ho naklonujte a začnite od začnite-tuvetvy:


git clone git@github.com:<your-username>/fullstack-resourcify.git

Keď potiahnete vetvu štart-tu:

  • Otvorte projekt pomocou preferovaného editora kódu

  • Zmeňte adresár na frontend/

  • Inštalovať závislosti: priadza

  • Spustite vývojový server: yarn dev·

Náhľad by mal vyzerať asi takto:

Changing user name

Názov vykreslený v navigačnom paneli – vpravo hore – je stavová premenná definovaná v hlavnom komponente aplikácie. Rovnaká premenná sa odovzdá na navigačný panel aj domovskú stránku. Jednoduchý formulár použitý vyššie v skutočnosti aktualizuje stavovú premennú „name“ z komponentu EditPage.

Dva prístupy uvedené nižšie sa budú venovať podrobnostiam implementácie:

Prvý prístup: useState

useState()

useState je jedným z najbežnejšie používaných hákov React, umožňuje vám vytvárať a mutovať stav v komponente React Functional. Komponent useState má skutočne jednoduchú implementáciu a ľahko sa používa: na vytvorenie nového stavu musíte zavolať useState s počiatočnou hodnotou vášho stavu a hák useState vráti pole obsahujúce dve premenné: prvá je stav premenná, ktorú môžete použiť na odkazovanie na svoj stav, a druhá funkcia, ktorú používate na zmenu hodnoty stavu: celkom jednoduché.

Čo keby sme to videli v akcii? Názov vykreslený v navigačnom paneli – vpravo hore – je stavová premenná definovaná v hlavnom komponente aplikácie. Rovnaká premenná sa odovzdá na navigačný panel aj domovskú stránku. Jednoduchý formulár použitý vyššie v skutočnosti aktualizuje stavovú premennú „name“ z komponentu EditPage. Zrátané a podčiarknuté: useState je základný hák, ktorý akceptuje počiatočný stav ako parameter a vracia dve premenné obsahujúce dve hodnoty, stavovú premennú obsahujúcu počiatočný stav a funkciu nastavovača pre rovnakú stavovú premennú.

Poďme si to rozobrať a uvidíme, ako to bolo implementované na prvom mieste.

  1. Vytvorenie stavovej premennej „name“:

./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: &#36;{name}`);

 return (...)};

Rekvizity

Rekvizity sú jedným zo základných stavebných kameňov komponentu React, koncepčne, ak si predstavíte funkčný komponent React ako funkciu Javascript, potom rekvizity nie sú nič viac ako parametre funkcie, kombinácia rekvizít a háku useState vám môže ponúknuť solídny rámec. pre správu stavu cez jednoduchú aplikáciu React.

React rekvizity sa prenášajú ako atribúty do vlastných komponentov. Atribúty odovzdané ako rekvizity môžu byť zničené z objektu rekvizity, keď ho prijmete ako argument, podobne ako toto:

Odovzdávanie rekvizít

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

Podpery možno akceptovať a použiť vo funkčnom komponente podobne ako argumenty normálnej funkcie. Je to preto, že „meno“ je odovzdané ako rekvizita komponentu Home, takže ho môžeme vykresliť v rovnakom komponente. V nasledujúcom príklade prijímame odovzdanú rekvizitu pomocou deštruktívnej syntaxe na extrahovanie vlastnosti name z objektu rekvizity.

Prijímanie rekvizít

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

Tip pre profesionálov

Otvorte konzolu prehliadača a všimnite si, ako sa všetky komponenty používajúce podperu „názov“ znova vykresľujú, keď sa stav zmení. Pri manipulácii s premennou stavu React uloží ďalší stav, znova vykreslí váš komponent s novými hodnotami a aktualizuje používateľské rozhranie.

Components Re-rendering

nevýhody stavu použitia

Podpery-vŕtanie

Vŕtanie rekvizít je termín označujúci hierarchiu komponentov, kde množina komponentov vyžaduje určité rekvizity poskytované nadradeným komponentom, bežným riešením, ktoré zvyčajne používajú neskúsení vývojári, je preniesť tieto rekvizity cez celý reťazec komponentov, problém s týmto prístup spočíva v tom, že zmena ktorejkoľvek z týchto rekvizít spustí celý reťazec komponentov na opätovné vykreslenie, čím sa efektívne spomalí celá aplikácia v dôsledku týchto nepotrebných renderov, komponentov v strede reťazca, ktoré tieto rekvizity nevyžadujú. pôsobiť ako médium na prenášanie rekvizít.

Príklad:

  • Stavová premenná bola definovaná v hlavnom komponente aplikácie pomocou háku useState().

  • Do komponentu Navbar bola odovzdaná podpera názvu

  • Rovnaká rekvizita akceptovaná v navigačnom paneli a odovzdaná ako rekvizita ešte raz komponentu UserDropdown

  • UserDropdown je posledný podradený prvok, ktorý akceptuje rekvizitu.

Prop-drilling

./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>
    </>
  );
}

Predstavte si, aké ťažké je udržiavať aplikáciu React s rôznymi vrstvami komponentov, ktoré prechádzajú a vykresľujú rovnaký stav.

Rastúca zložitosť a kvalita kódu

S použitím useState a rekvizít ako jediného prostriedku na riadenie stavu v aplikácii reakcie môže kódová základňa rýchlo rásť v zložitosti, pričom musí spravovať desiatky alebo stovky stavových premenných, ktoré môžu byť navzájom duplikované, rozptýlené v rôznych súboroch a komponenty môžu byť dosť skľučujúce, akákoľvek zmena danej stavovej premennej si bude vyžadovať starostlivé zváženie závislostí medzi komponentmi, aby sa predišlo akémukoľvek potenciálnemu dodatočnému vykresľovaniu v už aj tak pomalej aplikácii.

Druhý prístup: Kontextové API

Kontextové API je pokus Reactu vyriešiť nevýhody iba používania rekvizít a useState na správu stavu, najmä kontextové API prichádza ako odpoveď na vyššie uvedený problém týkajúci sa potreby odovzdať rekvizity do celého stromu komponentov. Pomocou kontextu môžete definovať stav pre údaje, ktoré považujete za globálne, a pristupovať k ich stavu z ľubovoľného bodu v strome komponentov: už žiadne vŕtanie s podperami.

Je dôležité poukázať na to, že kontextové API bolo pôvodne navrhnuté tak, aby vyriešilo problém globálneho zdieľania údajov, údajov, ako sú témy používateľského rozhrania, overovacie informácie, ktoré sú naším prípadom použitia, jazyky a podobne), pre iné typy údajov, ktoré je potrebné zdieľať. medzi viac ako jedným komponentom, ale nemusí byť nevyhnutne globálny pre všetky aplikácie, kontext nemusí byť najlepšou voľbou, v závislosti od prípadu použitia môžete zvážiť iné techniky, ako napríklad komponentné zloženie, čo je mimo rozsahu tohto článku.

Prepnutie do kontextu

Vytvorenie kontextu Auth

createContext je jednoduchý, vytvára novú kontextovú premennú, zaberá jeden voliteľný parameter: predvolenú hodnotu kontextovej premennej.

Pozrime sa na to v akcii, najprv vytvorte nový priečinok „contexts“ a v ňom nový súbor „Auth.jsx“. Aby sme vytvorili nový kontext, musíme vyvolať funkciu createContext(), priradiť vrátenú hodnotu novej premennej Auth, ktorá bude exportovaná ďalej:

./src/contexts/Auth.jsx

import { createContext } from "react";

export const Auth = createContext();

Poskytnite kontext overenia

Teraz musíme odhaliť kontextovú premennú „Auth“, ktorú sme vytvorili predtým, aby sme to dosiahli, používame poskytovateľa kontextu, poskytovateľ kontextu je komponent, ktorý má „hodnotovú“ podperu, túto podperu môžeme použiť na zdieľanie hodnoty – názvu – naprieč stromom komponentov obalením stromu komponentu komponentom poskytovateľa túto hodnotu sprístupníme odkiaľkoľvek v strome komponentov bez toho, aby sme museli túto podperu odovzdávať každému podriadenému komponentu jednotlivo.

V našom príklade autentifikácie potrebujeme premennú na uloženie objektu používateľa a nejaký druh nastavovača na manipuláciu s touto stavovou premennou, toto je perfektný prípad použitia pre useState. Pri používaní kontextu sa musíte uistiť, že definujete údaje, ktoré chcete poskytnúť, a odovzdávate tieto údaje – v našom príklade používateľa – do všetkých stromov komponentov vnorených vo vnútri, takže definujte nového používateľa stavovej premennej v komponente poskytovateľa a nakoniec odovzdáme užívateľa aj setUser do poľa ako hodnotu, ktorú poskytovateľ vystaví stromu komponentov:

./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>;
};

Ďalšia vec, ktorú môžeme urobiť, je presunúť našu stavovú premennú „name“ z hlavného komponentu aplikácie do kontextu Auth a vystaviť ju vnoreným komponentom:

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>;
};

Teraz už zostáva len vnorenie našej aplikácie do rovnakého komponentu AuthProvider, ktorý sme práve exportovali.

./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>
);

Pretože vykresľujeme podperu potomkov v rámci Auth.Provider, všetky prvky, ktoré sú vnorené do komponentu AuthProvider, sú teraz schopné využiť hodnotu prop, ktorú sme odovzdali Auth.Provider. Môže sa to zdať mätúce, ale akonáhle s tým experimentujete, skúste poskytnúť a konzumovať globálny – kontext – stav. Koniec koncov, zmysel mi to dávalo až po experimentovaní s kontextovým API.

Používanie kontextu overenia

Posledný krok je jednoduchý, používame kontextový hák "useContext" na prístup k hodnote, ktorú poskytuje poskytovateľ kontextu "Auth", čo je v našom prípade pole obsahujúce user a setUser, v nasledujúcom kóde sme schopní použite useContext na použitie kontextu Auth v navigačnom paneli. Je to možné len preto, že Navbar je vnorený do komponentu App a keďže AuthProvider obklopuje komponent App, hodnotu prop je možné použiť iba pomocou háku useContext. Ďalší úžasný nástroj, ktorý React poskytuje hneď po vybalení na správu akýchkoľvek údajov, ku ktorým je možné pristupovať globálne a tiež s nimi môže manipulovať akýkoľvek spotrebiteľský komponent.

./src/components/Navbar.jsx

export default function Navbar() {
 const [name, setName] = useContext(Auth);
 console.log(name)

 return (...)};

Všimnite si, že vo funkčnom komponente Navbar() už neprijímame žiadne rekvizity. Namiesto toho používame useContext(Auth) na použitie kontextu Auth, pričom zachytíme názov aj setName. To tiež znamená, že už nemusíme odovzdávať rekvizitu Navbar:

./src/App.jsx

// ... //
return (
   <BrowserRouter>
     <div className="h-screen">
       <Navbar/> // no need to pass prop anymore
// ... //

Aktualizácia kontextu overenia

Na manipuláciu so stavovou premennou „name“ môžeme použiť aj poskytnutú funkciu setName:

./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");

Predstavujeme háčik useReducer().

V predchádzajúcom príklade sme použili kontextové API na správu a zdieľanie nášho stavu v strome komponentov, možno ste si všimli, že stále používame useState ako základ našej logiky, a to je väčšinou v poriadku, pretože náš stav je stále jednoduchý objekt. v tomto bode, ale ak by sme chceli rozšíriť možnosti nášho overovacieho toku, určite budeme musieť ukladať viac než len e-mail aktuálne prihláseného používateľa, a tu sa vrátime späť k obmedzeniam, do ktorých sme predtým v súvislosti s použitie useState s komplexným stavom, našťastie, React rieši tento problém poskytnutím alternatívy k useState na správu komplexného stavu: zadajte useReducer.

useReducer si možno predstaviť ako zovšeobecnenú verziu useState, vyžaduje dva parametre: funkciu redukcie a počiatočný stav.

Pre počiatočný stav nie je nič zaujímavé, kúzlo sa deje vo vnútri funkcie reduktora: kontroluje typ akcie, ktorá sa vyskytla, a v závislosti od tejto akcie reduktor určí, ktoré aktualizácie sa použijú na stav a vráti svoju novú hodnotu. .

Pri pohľade do nižšie uvedeného kódu má funkcia redukcie dva možné typy akcií:

  • "PRIHLÁSENIE": v takom prípade sa stav používateľa aktualizuje novými používateľskými povereniami poskytnutými v užitočnej časti akcie.

  • "LOGOUT": v takom prípade sa stav používateľa odstráni z lokálneho úložiska a nastaví sa späť na hodnotu null.

Je dôležité poznamenať, že objekt akcie obsahuje pole typu, ktoré určuje, aká logika sa má použiť, a voliteľné pole užitočného zaťaženia na poskytnutie údajov, ktoré sú potrebné na aplikáciu tejto logiky.

Nakoniec hák useReducer vráti aktuálny stav a funkciu odoslania, ktorú používame na odovzdanie akcie reduktorovi.

Pre zvyšok logiky je to totožné s predchádzajúcim príkladom:

./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>
  );
};

Odosielanie akcií namiesto použitia funkcie setState setter – napr.: setName –

Ako sme práve spomenuli, na odovzdanie akcie reduktorovi používame funkciu odoslania, v nasledujúcom kóde spustíme akciu PRIHLÁSENIE a poskytneme e-mail používateľa ako užitočné zaťaženie, teraz sa aktualizuje stav používateľa a táto zmena sa spustí opätovné vykreslenie všetkých komponentov prihlásených do stavu používateľa. Je dôležité zdôrazniť, že opätovné vykreslenie sa spustí iba vtedy, ak nastane skutočná zmena stavu, žiadne opätovné vykreslenie, ak reduktor vráti rovnaký predchádzajúci stav.

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 (...)};

Prihlásenie používateľa

JWT Local storage

Tip pre profesionálov

Všimnite si, ako je objekt používateľa, ktorý dostaneme po úspešnom prihlásení, teraz uložený v localStorage.

Vlastný háčik na prihlásenie

Teraz, keď už dobre ovládame useReducer, môžeme ďalej zapuzdreť našu logiku prihlásenia a odhlásenia do ich vlastných samostatných vlastných háčikov, jediným volaním háčika Login môžeme spracovať volanie API k prihlasovacej trase, získať nového používateľa. poverenia a uložte ich do lokálneho úložiska, odošlite volanie LOGIN na aktualizáciu stavu používateľa, a to všetko pri riešení chýb:

./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 };
};

Poznámka: pre pokročilejších používateľov React medzi čitateľmi by vás mohlo zaujímať, prečo sme nepoužili funkciu lenivej inicializácie useReducer na získanie poverení používateľa, useReducer akceptuje tretí voliteľný parameter nazývaný init funkcia, táto funkcia sa používa v prípade musíme použiť určitú logiku predtým, než získame počiatočnú hodnotu stavu, dôvod, prečo sme sa pre to nerozhodli, je jednoduchá záležitosť oddelenia obáv, kód je takto jednoduchší na pochopenie a v dôsledku toho aj jednoduchší na údržbu .

Prihlasovacia stránka

Tu je návod, ako vyzerá horná časť našej prihlasovacej stránky po použití háku useLogin() na extrakciu prihlasovacej funkcie a vyvolaní prihlasovacej funkcie s prihlasovacími údajmi zaslanými používateľom:

// ... ... //
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 (...)
// ... ... //

Funkciu Odoslať tiež deaktivujeme, keď používateľ odošle formulár:

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

A vykreslenie akýchkoľvek chýb overenia, ktoré dostaneme z nášho backendu:

{
  error && <span className="text-red-500 p-2">{error.message}</span>;
}

Rendering Errors

Udržiavanie stavu používateľa

Možno sa čudujete, prečo musíme ukladať objekt používateľa do localStorage, jednoducho povedané, chceme ponechať používateľa prihláseného, ​​kým nevyprší platnosť tokenu. Použitie localStorage je skvelý spôsob, ako ukladať kúsky JSON, rovnako ako v našom príklade. Všimnite si, ako dôjde k vymazaniu stavu, ak po prihlásení obnovíte stránku. Dá sa to jednoducho vyriešiť pomocou háku useEffect na kontrolu, či máme uložený objekt používateľa v localStorage, ak nejaký existuje, používateľa prihlásime automaticky:

// ... ... //
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>
  );
};

Vlastné háčiky na odhlásenie

To isté platí pre háčik Logout, tu odosielame akciu LOGOUT na odstránenie aktuálnych používateľských poverení zo stavu aj lokálneho úložiska:

./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 };
};

Odhlásenie používateľa

Ak chcete používateľa odhlásiť, pridajte udalosť kliknutia do tlačidla Odhlásiť, ktoré sa nachádza v súbore UserDropdown.jsx, a narábajte s ním podľa toho:

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

User Logout

Ochrana reakčných ciest

Posledným krokom pri implementácii našej aplikácie je využiť globálny stav používateľa na ovládanie navigácie používateľa, čo je rýchle pripomenutie toho, aké správanie by sme mali dosiahnuť: používateľa najprv privíta prihlasovacia stránka, od tohto bodu má používateľ prístup iba na domovskú stránku. po úspešnom prihlásení, podobne bude užívateľ po odhlásení presmerovaný na prihlasovaciu stránku.

Dosiahneme to pomocou knižnice Reag-router-dom definovaním 2 ciest: „/“ a „/login“, pomocou globálneho stavu autorizácie kontrolujeme, ktorý komponent sa má na každej trase vykresliť., auth vyhodnocujúce na null predstavuje neovereného používateľa a naopak:

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

Rekapitulačný diagram

Diagram

Zabaliť

V tomto článku sme sa pokúsili vyriešiť jednoduchý, ale veľmi bežný prípad použitia implementácie správy stavu pre pracovný postup overovania, pričom sme prešli rôznymi prístupmi, zdôvodnením každého z nich a ich kompromismi. Správa stavu v klientskych rámcoch a najmä v Reacte je jednou z najdiskutovanejších tém vo frontendovej komunite, jednoducho preto, že môže buď zvýšiť alebo narušiť výkon a škálovateľnosť vašej aplikácie. Obrovské množstvo rôznych techník, vzorov, knižníc a nástrojov, ktoré sa snažia vyriešiť tento problém riadenia štátu, je ohromujúce. Naším cieľom bolo poskytnúť vám solídne pochopenie postupov, aby ste ich mohli implementovať vo svojej vlastnej aplikácii pre pokročilejších. techniky a vzory riadenia stavu v zložitejších aplikáciách, pozrite si náš ďalší článok, kde sa dostaneme do reduxu pre škálovateľné riadenie stavu v Reacte.

Už čoskoro

ContextAPI vs Redux Toolkit

Redux bol v komunite prijatý mnoho rokov pred súpravou nástrojov Redux, v skutočnosti bol RTK predstavený ako štartovacia šablóna na zavádzanie správy stavu redux v nových aplikáciách (jeho počiatočný názov bol „redux-starter-kit“ v októbri 2019), hoci dnes existuje všeobecný konsenzus medzi správcami Reduxu a komunitou, že súprava nástrojov Redux je platným spôsobom práce s reduxom. RTX abstrahuje veľa z logiky Redux, čo uľahčuje používanie, je oveľa menej podrobné a povzbudzuje vývojárov, aby dodržujte osvedčené postupy, jeden hlavný rozdiel medzi nimi je ten, že Redux bol vytvorený tak, aby neobsahoval názory, poskytoval minimálne API a očakával, že vývojári urobia väčšinu ťažkej práce napísaním vlastných knižníc pre bežné úlohy a riešením štruktúry kódu, to viedlo k pomalému vývojovému času a chaotickému kódu, Redux toolkit bol pridaný ako ďalšia vrstva abstrakcie, ktorá bráni vývojárom dostať sa do bežných úskalí, ďalšie informácie a zdôvodnenia od jeho správcov nájdete v oficiálnej dokumentácii tu.


Career Services background pattern

Kariérne služby

Contact Section background image

Ostaňme v kontakte

Code Labs Academy © 2024 Všetky práva vyhradené.