Állammenedzsment a reakcióban: gyakorlati példa

reagálni
állapotkezelés
kontextus api
Állammenedzsment a reakcióban: gyakorlati példa cover image

A React számos fejlesztő számára a dinamikus kliensoldali alkalmazások építésének megfelelő keretrendszere. Ezeknek az alkalmazásoknak a dinamikus jellege a rugalmasságból, valamint az ügyféloldalon elérhető képességek és szolgáltatások kibővített listájából fakad, ami lehetővé tette a fejlesztők számára, hogy pillanatok alatt teljes értékű alkalmazásokat készítsenek, amelyek pillanatok alatt betöltődnek a böngészőbe, ami nem volt lehetséges (vagy nagyon nehézkes) a statikus web napjaiban.

A lehetőségek e bővülésével megjelent az állapotkezelés koncepciója, mivel az ügyféloldali alkalmazások komplexitásának növekedésével a helyi állapot megtartásának igénye önmagában szűk keresztmetszetté válik, ha nem kezelik megfelelően és nem a méretezhetőséget szem előtt tartva.

Ezzel a kérdéssel számos keretrendszer foglalkozott, különböző megközelítéseket követve és különböző részproblémacsoportokra összpontosítva, ezért fontos a választott keret ökoszisztémájának magas szintű megértése az egyes alkalmazások szükségleteinek felméréséhez és a megfelelő megközelítés alkalmazásához. mérőszámok. Ez a cikk rövid áttekintést nyújt a gyakori állapotkezelési problémákról, és megpróbál különböző megközelítéseket bevezetni (useState, Context API) válaszként. Noha ez a cikk több megoldást is bemutat, csak a kisebb léptékű kihívásokra összpontosít, a következő cikkekben haladóbb témákkal foglalkozunk.

Hitelesítési munkafolyamat

A cikkben bemutatott kód itt.

Az élő előnézeti link itt érhető el.

Tekintsük azt az esetet, amikor egy React alkalmazás hitelesítési folyamatát hajtjuk végre.

User Login

A fenti GIF-en látható módon lehetővé akarjuk tenni a felhasználók számára, hogy hitelesítő adatokkal bejelentkezzenek vagy regisztráljanak az alkalmazásunkba. Érvényes hitelesítő adatok megadása esetén a felhasználó bejelentkezik, az alkalmazás automatikusan a kezdőlapra navigál, és a felhasználó folytathatja az alkalmazás használatát.

Hasonlóképpen, ha a felhasználó kijelentkezik, a kezdőlap erőforrásai bejelentkezés mögött védve lesznek, a bejelentkezési oldal lesz az egyetlen oldal, amelyet a felhasználó elérhet.

Ha ezt a munkafolyamatot a megvalósítás szempontjából tekintjük, akkor egy App nevű fő komponensünk lenne, az App komponens két oldal egyikére irányítja át a felhasználót: Kezdőlap vagy Bejelentkezés, a felhasználó aktuális állapota (bejelentkezett, kijelentkezett) határozza meg, hogy melyik oldalra. oldal, amelyre a felhasználó át van irányítva, a felhasználó aktuális állapotának változása (például bejelentkezettről kijelentkezettre vált) azonnali átirányítást kell, hogy indítson a megfelelő oldalra.

State

Ahogy a fenti ábrán is látható, azt szeretnénk, hogy az App komponens figyelembe vegye az aktuális állapotot, és a két oldal közül csak az egyiket jelenítse meg – a Kezdőlap vagy a Bejelentkezés – az aktuális állapot alapján.

Ha a felhasználó nulla, az azt jelenti, hogy nincs hitelesített felhasználónk, ezért automatikusan a bejelentkezési oldalra lépünk, és feltételes megjelenítéssel védjük a kezdőlapot. Ha a felhasználó létezik, akkor az ellenkezőjét csináljuk.

Most, hogy tisztában vagyunk azzal, hogy mit kell megvalósítani, vizsgáljunk meg néhány lehetőséget, de először állítsuk be a React projektünket,

A projekt repo tartalmaz egy minta háttéralkalmazást, amelyet a frontend oldal megvalósítására fogunk használni (nem megyünk bele, mert itt nem ez a fő hangsúly, de a kódot szándékosan egyszerűnek tartottuk, így nem lesz nehéz dolga )

Kezdjük a következő oldalak és összetevők létrehozásával:

  • Kezdőlap

  • Bejelentkezési oldal

  • EditUser oldal

  • Navbar komponens

  • UserDropdown komponens

A többoldalas React alkalmazásnak megfelelő navigációra van szüksége, ehhez a react-router-dom segítségével létrehozhatunk egy globális böngésző útválasztó kontextust és regisztrálhatunk különböző React útvonalakat.


yarn add react-router-dom

Tudjuk, hogy sok olvasó jobban szereti a követést és az oktatóanyagokat, ezért itt van a kezdősablon, amely felgyorsítja a lépést. Ez a kezdő ág a DaisyUI-t használja az előre meghatározott TailwindCSS JSX-komponensekhez. Tartalmazza az összes összetevőt, oldalt és a már beállított útválasztót. Ha azt fontolgatja, hogy követi ezt az oktatóanyagot, és saját maga építi fel a teljes hitelesítési folyamatot egyszerű lépések követésével, először a tárhely elágazásával kezdje. Miután elágazta a tárat, klónozza azt, és kezdje a start-hereelágazással:


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

Miután meghúzta a start-itt ágat:

  • Nyissa meg a projektet a kívánt kódszerkesztővel

  • Módosítsa a könyvtárat a következőre: frontend/

  • Függőségek telepítése: fonal

  • Indítson el egy fejlesztői szervert: yarn dev·

Az előnézetnek valahogy így kell kinéznie:

Changing user name

A Navbarban megjelenített név – jobb felső sarokban – egy állapotváltozó, amelyet az alkalmazás fő összetevőjében határoztak meg. Ugyanaz a változó kerül átadásra a Navbarnak és a Kezdőlapnak is. A fent használt egyszerű űrlap valójában frissíti a „name” állapotváltozót az EditPage komponensből.

Az alábbiakban bemutatott két megközelítés a végrehajtás részleteire vonatkozik:

Első megközelítés: useState

useState()

A useState az egyik leggyakrabban használt React hook, lehetővé teszi állapot létrehozását és mutációját a React Functional komponensben. A useState komponens nagyon egyszerű megvalósítású és könnyen használható: új állapot létrehozásához meg kell hívni a useState-et az állapot kezdeti értékével, és a useState hook két változót tartalmazó tömböt ad vissza: az első az állapot változó, amellyel az állapotára hivatkozhat, a második pedig egy függvény, amellyel megváltoztathatja az állapot értékét: elég egyszerű.

Mit szólnál, ha ezt működés közben látnánk? A Navbarban megjelenített név – jobb felső sarokban – egy állapotváltozó, amelyet az alkalmazás fő összetevőjében határoztak meg. Ugyanaz a változó kerül átadásra a Navbarnak és a Kezdőlapnak is. A fent használt egyszerű űrlap valójában frissíti a „name” állapotváltozót az EditPage komponensből. A lényeg a következő: a useState egy alapvető horog, amely elfogad egy kezdeti állapotot paraméterként, és két változót ad vissza, amelyek két értéket tartalmaznak, a kezdeti állapotot tartalmazó állapotváltozót és ugyanahhoz az állapotváltozóhoz egy beállító függvényt.

Bontsuk fel, és nézzük meg, hogyan valósították meg először.

  1. A „name” állapotváltozó létrehozása:

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

Kellékek

A kellékek a react komponens egyik alapvető építőkövei, fogalmilag, ha a React funkcionális komponenst Javascript függvénynek tekinti, akkor a kellékek nem mások, mint a függvény paraméterei, a kellékek és a useState hook kombinálása szilárd keretet kínálhat. állapot kezeléséhez egy egyszerű React alkalmazáson keresztül.

A React kellékek attribútumként kerülnek átadásra az egyéni összetevőknek. A kellékként átadott attribútumok destrukturálhatók a props objektumból, ha argumentumként fogadjuk el, ehhez hasonlóan:

Kellékek átadása

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

A kellékek a normál függvény argumentumokhoz hasonlóan funkcionális komponensen belül is elfogadhatók és használhatók. Ez azért van, mert a „név” a Home komponensnek kellékként van átadva, így ugyanabban a komponensben jeleníthetjük meg. A következő példában elfogadjuk az átadott propot a destructuring szintaxis használatával, hogy kivonjuk a name tulajdonságot a props objektumból.

Kellékek elfogadása

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

Profi tipp

Nyissa meg a böngésző konzolját, és figyelje meg, hogy az állapot megváltozásakor a „name”-t használó összes összetevő hogyan jelenik meg újra. Az állapotváltozók manipulálásakor a React eltárolja a következő állapotot, újra rendereli az összetevőt az új értékekkel, és frissíti a felhasználói felületet.

Components Re-rendering

useState hátrányok

Kellékek-fúrás

A kellékek fúrása egy olyan kifejezés, amely az összetevők hierarchiájára utal, ahol egy komponenskészlethez egy szülőkomponens által biztosított bizonyos kellékekre van szükség. Egy gyakori megoldás, amelyet a tapasztalatlan fejlesztők általában úgy használnak, hogy ezeket a kellékeket a teljes komponensláncon keresztül továbbítják. Az a megközelítés, hogy ezen kellékek bármelyikének megváltoztatása a komponensek teljes láncának újrarenderelését váltja ki, ami hatékonyan lelassítja az egész alkalmazást a szükségtelen renderelések következtében, a lánc közepén lévő komponenseket, amelyekhez nincs szükség ezekre a kellékekre. médiumként működnek a kellékek átviteléhez.

Példa:

  • Az állapotváltozót a useState() hook segítségével határozták meg a fő alkalmazáskomponensben

  • A Navbar komponensnek egy névjavaslatot adtak át

  • Ugyanaz a javaslat elfogadva a Navbarban, és újra átadva propként a UserDropdown komponensnek

  • A UserDropdown az utolsó gyermekelem, amely elfogadja a propot.

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

Képzelje el, milyen nehéz olyan React alkalmazást karbantartani, ahol az összetevők különböző rétegei mindegyike ugyanazt az állapotot adja át és jeleníti meg.

Növekvő komplexitás és kódminőség

A useState és a props használatával, mint az állapotkezelés egyetlen eszközével egy react alkalmazásban, a kódbázis gyorsan bonyolultabbá válhat, és több tíz vagy száz állapotváltozót kell kezelnie, amelyek egymás duplikátumai lehetnek, szétszórva különböző fájlok között és A komponensek meglehetősen ijesztőek lehetnek, egy adott állapotváltozó bármilyen megváltoztatása megköveteli az összetevők közötti függőségek alapos mérlegelését, hogy elkerüljük az esetleges további újrarenderelést egy amúgy is lassú alkalmazásban.

Második megközelítés: Context API

A Context API a React kísérlete arra, hogy megoldja a csak props és useState használatának hátrányait az állapotkezeléshez, különösen, a kontextus API választ ad arra a korábban említett problémára, hogy a kellékeket át kell adni a teljes komponensfán. A kontextus használatával meghatározhat egy állapotot a globálisnak ítélt adatokhoz, és az összetevőfa bármely pontjáról hozzáférhet az állapotához: nincs több támasztófúrás.

Fontos kiemelni, hogy a kontextus API-t eredetileg arra tervezték, hogy megoldja a globális adatmegosztás problémáját, az adatok, például a felhasználói felület témái, a hitelesítési információk, amelyek a mi használati esetünk, a nyelvek és hasonlók), más típusú adatok megosztására. egynél több összetevő közül, de nem feltétlenül globális az összes alkalmazásra, előfordulhat, hogy a kontextus nem a legjobb megoldás, a használati esettől függően más technikákat is fontolóra vehet, például összetevő összetétele, amely nem tartozik e cikk hatálya alá.

Váltás kontextusra

A hitelesítési környezet létrehozása

A createContext egyszerű, új környezeti változót hoz létre, egyetlen opcionális paramétert vesz fel: a kontextusváltozó alapértelmezett értékét.

Lássuk ezt működés közben, először hozzon létre egy új „contexts” mappát, és egy új fájlt az „Auth.jsx” belsejében. Új kontextus létrehozásához meg kell hívnunk a createContext() függvényt, és a visszaadott értéket hozzá kell rendelnünk egy új Auth változóhoz, amelyet a következőképpen exportálunk:

./src/contexts/Auth.jsx

import { createContext } from "react";

export const Auth = createContext();

Adja meg a hitelesítési kontextust

Most meg kell jelenítenünk a korábban létrehozott "Auth" kontextusváltozót, ennek eléréséhez a kontextusszolgáltatót használjuk, a kontextusszolgáltató egy olyan komponens, aminek van "érték" propja, ezzel a tulajdonsággal megoszthatunk egy értéket - név – az összetevőfán keresztül az összetevőfát a szolgáltató komponenssel burkolva az adott értéket a komponensfán belül bárhonnan elérhetővé tesszük anélkül, hogy ezt a támasztékot külön-külön át kellene adni az egyes alárendelt összetevőknek.

A hitelesítési példánkban szükségünk van egy változóra a felhasználói objektum tárolására, és valamilyen beállítóra az állapotváltozó manipulálásához, ez a useState tökéletes használati esete. A Context használatakor meg kell győződnie arról, hogy definiálja a megadni kívánt adatokat, és átadja ezeket az adatokat – a példánkban felhasználónak – az összes benne beágyazott összetevőfának, tehát definiáljon egy új felhasználó állapotváltozót a szolgáltató összetevőn belül, és végül a usert és a setUser-t is átadjuk egy tömbön belül, mint az az érték, amelyet a szolgáltató az összetevőfának tesz közzé:

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

Egy másik dolog, amit tehetünk, hogy áthelyezzük a „name” állapotváltozónkat az alkalmazás fő összetevőjéből az Auth kontextusba, és beágyazott összetevőknek tesszük ki:

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

Most már csak az van hátra, hogy beágyazzuk az alkalmazásunkat ugyanabba az AuthProvider-komponensbe, amelyet éppen exportáltunk.

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

Mivel az Auth.Provider-en belül jelenítjük meg a gyermek propokat, az AuthProvider összetevőbe beágyazott összes elem képes felhasználni az Auth.Provider-nek átadott értéket. Zavarba ejtőnek tűnhet, de ha egyszer kísérletezik vele, próbáljon meg egy globális – Kontextus – állapotot biztosítani és felhasználni. Végül is csak a Context API-val való kísérletezés után volt értelme számomra.

A hitelesítési kontextus felhasználása

Az utolsó lépés egyszerű, a "useContext" kontextus hook segítségével elérjük az "Auth" kontextusszolgáltatója által biztosított értéket, ami esetünkben a user és a setUser tömbje, a következő kódban képesek vagyunk használja a useContext-et a navigációs sávon belüli hitelesítési kontextus felhasználásához. Ez csak azért lehetséges, mert a Navbar az App komponensbe van beágyazva, és mivel az AuthProvider körbeveszi az App komponenst, az értéktámasz csak a useContext hook használatával használható fel. Egy másik nagyszerű eszköz, a React már a dobozból kiindulva biztosít minden olyan adat kezelését, amelyhez globálisan hozzá lehet férni, és bármely fogyasztói összetevővel manipulálható.

./src/components/Navbar.jsx

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

 return (...)};

Figyelje meg, hogy a Navbar() funkcionális komponensben már nem fogadunk el kellékeket. Ehelyett a useContext(Auth) függvényt használjuk az Auth kontextus felhasználására, mind a name, mind a setName megragadásával. Ez azt is jelenti, hogy többé nem kell átadnunk a kelléket a Navbarnak:

./src/App.jsx

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

A hitelesítési kontextus frissítése

A megadott setName függvényt is használhatjuk a „name” állapotváltozó manipulálására:

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

A useReducer() hook bemutatása

Az előző példában a kontextus API-t használtuk állapotunk kezelésére és megosztására az összetevőfán, és észrevehette, hogy még mindig a useState-et használjuk logikánk alapjaként, és ez többnyire rendben van, mivel az állapotunk még mindig egy egyszerű objektum. ezen a ponton, de ha bővíteni akarjuk a hitelesítési folyamatunk lehetőségeit, akkor minden bizonnyal többet kell tárolnunk, mint a jelenleg bejelentkezett felhasználó e-mailjeit, és itt térünk vissza azokhoz a korlátokhoz, amelyekbe korábban belementünk. a useState használata összetett állapottal, szerencsére a React megoldja ezt a problémát azáltal, hogy alternatívát kínál a useState helyett az összetett állapot kezelésére: írja be a useReducer-t.

A useReducer a useState általánosított változataként fogható fel, két paraméterre van szükség: egy reduktor funkcióra és egy kezdeti állapotra.

A kezdeti állapothoz nincs semmi érdekes, a varázslat a reduktor funkción belül történik: ellenőrzi a megtörtént művelet típusát, és ettől a művelettől függően a reduktor meghatározza, hogy milyen frissítéseket alkalmazzon az állapotra, és visszaadja az új értékét. .

Az alábbi kódot nézve a reduktor funkciónak két lehetséges művelettípusa van:

  • "BEJELENTKEZÉS": ebben az esetben a felhasználói állapot frissül az új felhasználói hitelesítési adatokkal, amelyek a műveleti adattartalomban találhatók.

  • "LOGOUT": ebben az esetben a felhasználói állapot törlődik a helyi tárolóból, és nullára áll vissza.

Fontos megjegyezni, hogy a műveletobjektum tartalmaz egy típusmezőt, amely meghatározza, hogy milyen logikát alkalmazzon, és egy opcionális hasznos adatmezőt is, amely az adott logika alkalmazásához szükséges adatokat szolgáltatja.

Végül a useReducer hook visszaadja az aktuális állapotot és egy diszpécser függvényt, amellyel egy műveletet továbbítunk a reduktornak.

A logika többi részét illetően ez megegyezik az előző példával:

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

Műveletek küldése a setState beállító függvény használata helyett – pl.: setName –

Ahogy az imént említettük, a diszpécser funkciót használjuk egy művelet átadására a reduktornak, a következő kódban elindítunk egy LOGIN műveletet és a felhasználói e-mail-címet rakományként adjuk meg, most a felhasználói állapot frissül, és ez a változás aktiválódik. a felhasználói állapotra előfizetett összes összetevő újramegjelenítése. Fontos kiemelni, hogy az újbóli renderelés csak akkor indul el, ha tényleges változás következik be az állapotban, nem történik újra renderelés, ha a reduktor ugyanazt az előző állapotot adja vissza.

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

Bejelentkezés

JWT Local storage

Profi tipp

Figyelje meg, hogy a sikeres bejelentkezés után kapott felhasználói objektum most hogyan kerül tárolásra a localStorage-ban.

Egyedi horog a bejelentkezéshez

Most, hogy jól tudjuk kezelni a useReducer-t, a bejelentkezési és kijelentkezési logikánkat tovább foglalhatjuk saját különálló hook-okba, a Login hook egyetlen hívásával kezelhetjük a bejelentkezési útvonalra irányuló API-hívást, visszakereshetjük az új felhasználót. hitelesítő adatokat, és tárolja őket a helyi tárhelyen, küldjön egy LOGIN hívást a felhasználói állapot frissítéséhez, miközben a hibakezeléssel foglalkozik:

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

Megjegyzés: az olvasók közül haladóbb React-felhasználók számára felmerülhet a kérdés, hogy miért nem a useReducer lusta inicializálási funkcióját használtuk a felhasználói hitelesítő adatok lekéréséhez, a useReducer elfogad egy harmadik opcionális paramétert, az init függvényt, ezt a funkciót akkor használják, ha alkalmaznunk kell némi logikát, mielőtt megkapjuk az állapot kezdeti értékét, az oka annak, hogy nem ezt választottuk, az aggodalmak egyszerű szétválasztásának kérdése, a kód így könnyebben érthető, és ennek következtében egyszerűbb a karbantartása .

Bejelentkezési oldal

Így néz ki a bejelentkezési oldalunk felső része, miután a useLogin() hook segítségével kibontottuk a bejelentkezési függvényt, és meghívtuk a bejelentkezési függvényt a felhasználó által megadott hitelesítő adatokkal:

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

A Küldés funkciót is letiltjuk, amikor a felhasználó elküldi az űrlapot:

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

És a háttérrendszerünktől kapott hitelesítési hibák megjelenítése:

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

Rendering Errors

A felhasználói állapot fenntartása

Felmerülhet benned a kérdés, hogy miért kell a felhasználói objektumot a localStorage-ban tárolnunk, egyszerűen fogalmazva, addig akarjuk bejelentkezve tartani a felhasználót, amíg a token le nem jár. A localStorage használata nagyszerű módja a JSON bitek tárolásának, akárcsak a példánkban. Figyelje meg, hogyan törlődik az állapot, ha frissíti az oldalt bejelentkezés után. Ez egyszerűen megoldható a useEffect hook segítségével, amellyel ellenőrizheti, hogy van-e tárolt felhasználói objektum a localStorage-ban, ha van, akkor automatikusan bejelentkezünk a felhasználóba:

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

Egyedi horgok a kijelentkezéshez

Ugyanez vonatkozik a Kijelentkezési hookra is, itt egy LOGOUT műveletet küldünk el, amely eltávolítja az aktuális felhasználói hitelesítő adatokat mind az állapotról, mind a helyi tárhelyről:

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

Felhasználói kijelentkezés

Egy felhasználó kijelentkeztetéséhez adjunk hozzá egy kattintási eseményt a UserDropdown.jsx fájlban található Kijelentkezés gombra, és ennek megfelelően kezeljük:

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

React Routes védelme

Alkalmazásunk megvalósításának utolsó lépése a globális felhasználói állapot kihasználása a felhasználói navigáció szabályozására, gyors emlékeztető arra, hogy milyen viselkedést kell elérni: kezdetben a felhasználót a bejelentkezési oldal köszönti, ettől kezdve a felhasználó csak a kezdőlapra férhet hozzá. a sikeres bejelentkezés után a felhasználó kijelentkezéskor is a bejelentkezési oldalra kerül.

Ezt a react-router-dom könyvtár segítségével érjük el, 2 útvonal definiálásával: "/" és "/login", a globális hitelesítési állapot segítségével szabályozzuk, hogy melyik komponenst jelenítse meg az egyes útvonalakon., az auth kiértékelés nullára nem hitelesített felhasználót jelent, és fordítva:

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

Összefoglaló diagram

Diagram

Befejezés

Ebben a cikkben megpróbáltuk kezelni az állapotkezelés megvalósításának egyszerű, de nagyon gyakori esetét egy hitelesítési munkafolyamathoz, áttekintve a különböző megközelítéseket, azok mögött meghúzódó indokokat és kompromisszumokat. Az állapotkezelés az ügyféloldali keretrendszerekben és különösen a Reactban az egyik legtöbbet emlegetett téma a frontend közösségben, egyszerűen azért, mert növelheti vagy megtörheti az alkalmazás teljesítményét és méretezhetőségét. A különböző technikák, minták, könyvtárak és eszközök puszta mennyisége, amelyek megpróbálják megoldani ezt az államigazgatási kérdést, elsöprő, célunk az volt, hogy alapos ismereteket adjunk a gyakorlatokról, hogy saját alkalmazásaiban alkalmazhassa, fejlettebbek számára. Az állapotkezelés technikái és mintái összetettebb alkalmazásokban, tekintse meg következő cikkünket, ahol a React méretezhető állapotkezelésének reduxjával foglalkozunk.

Hamarosan

ContextAPI vs Redux Toolkit

A Reduxot sok éven át alkalmazták a közösségben a Redux eszközkészlet előtt, valójában az RTK-t kezdősablonként vezették be a redux állapotkezelés elindításához az új alkalmazásokban (az eredeti neve „redux-starter-kit” volt 2019 októberében), bár ma általános konszenzus van a Redux karbantartói és a közösség között abban, hogy a Redux eszköztár a legmegfelelőbb módja a redux-szal való munkavégzésnek. Az RTX a Redux logikájának nagy részét elvonja, ami megkönnyíti a használatát, sokkal kevésbé bőbeszédű, és arra ösztönzi a fejlesztőket, hogy Kövesse a bevált gyakorlatokat, az egyik fő különbség a kettő között az, hogy a Reduxot úgy építették, hogy ne legyen véleménynyilvánítása, minimális API-t biztosítva, és a fejlesztőktől elvárják, hogy saját programkönyvtárakat írjanak a gyakori feladatokhoz, és foglalkozzanak a kódszerkezettel. ez lassú fejlesztési időt és zűrzavaros kódot eredményezett, a Redux eszközkészletet extra absztrakciós rétegként adták hozzá, amely megakadályozza, hogy a fejlesztők beleesjenek a gyakori buktatókba. További információkért és a karbantartói indoklásáért tekintse meg a hivatalos dokumentációt itt.


Career Services background pattern

Karrier szolgáltatások

Contact Section background image

Maradjunk kapcsolatban

Code Labs Academy © 2024 Minden jog fenntartva.