Valstybės valdymas reaguoja: praktinis pavyzdys

reaguoti
valstybės valdymas
konteksto api
Valstybės valdymas reaguoja: praktinis pavyzdys cover image

„React“ yra daugelio kūrėjų dinamiškų kliento programų kūrimo sistema. Dinamiškas šių programų pobūdis atsiranda dėl lankstumo ir išplėstinio kliento galimybių ir funkcijų sąrašo, leidžiančio kūrėjams sukurti visavertes programas, kurios per kelias sekundes įkeliamos į naršyklę, o tai nebuvo padaryta. įmanoma (arba labai sudėtinga) statinio žiniatinklio laikais.

Išplėtus galimybes, atsirado būsenos valdymo koncepcija, nes kliento programose didėjant sudėtingumui, poreikis išlaikyti vietinę būseną išauga ir tampa kliūtimi, jei nebus tinkamai tvarkoma ir galvojama apie mastelį.

Šis klausimas buvo sprendžiamas daugelyje sistemų, vadovaujantis skirtingais požiūriais ir sutelkiant dėmesį į skirtingus poproblemų rinkinius, todėl svarbu turėti aukšto lygio supratimą apie pasirinktos sistemos ekosistemą, kad būtų galima įvertinti kiekvienos programos poreikius ir taikyti teisingą požiūrį. metrikos. Šiame straipsnyje trumpai apžvelgsite dažniausiai pasitaikančias būsenos valdymo problemas ir bandysite į juos atsakyti įvairiais būdais (useState, Context API). Nors šiame straipsnyje bus pateikti keli sprendimai, dėmesys bus skiriamas tik mažesnio masto iššūkiams, o būsimuose straipsniuose apžvelgsime sudėtingesnes temas.

Autentifikavimo darbo eiga

Straipsnyje rodomą kodą galite rasti čia.

Tiesioginės peržiūros nuorodą galima pasiekti čia.

Apsvarstykite atvejį, kai įgyvendiname „React“ programos autentifikavimo procesą.

User Login

Kaip parodyta aukščiau esančiame GIF, norime leisti vartotojams prisijungti arba prisiregistruoti prie mūsų programos naudojant kredencialus. Jei buvo pateikti galiojantys kredencialai, vartotojas bus prisijungęs, programa automatiškai pereis į pagrindinį puslapį ir vartotojas galės toliau naudotis programa.

Panašiai, jei vartotojas atsijungia, pagrindinio puslapio ištekliai bus apsaugoti prisijungus, prisijungimo puslapis bus vienintelis vartotojui prieinamas puslapis.

Pagalvodami apie šią darbo eigą diegimo prasme, turėtume pagrindinį komponentą pavadinimu App, programos komponentas nukreips vartotoją į vieną iš dviejų puslapių: Pagrindinis arba Prisijungimas, dabartinė vartotojo būsena (prisijungęs, atsijungęs) nurodys, kuri puslapį, į kurį vartotojas nukreipiamas, dabartinės vartotojo būsenos pakeitimas (pvz., pakeitimas iš prisijungusio į atsijungtą) turėtų suaktyvinti momentinį peradresavimą į atitinkamą puslapį.

State

Kaip parodyta aukščiau esančioje iliustracijoje, norime, kad programos komponentas atsižvelgtų į dabartinę būseną ir pagal tą dabartinę būseną pateiktų tik vieną iš dviejų puslapių – Pagrindinis arba Prisijungimas.

Jei vartotojas yra nulinis, tai reiškia, kad neturime autentifikuoto vartotojo, todėl automatiškai pereiname į prisijungimo puslapį ir apsaugome pagrindinį puslapį naudodami sąlyginį atvaizdavimą. Jei vartotojas egzistuoja, elgiamės priešingai.

Dabar, kai puikiai suprantame, ką reikėtų įgyvendinti, išnagrinėkime keletą variantų, bet pirmiausia sukurkime savo „React“ projektą,

Projekto atpirkimo versijoje yra pavyzdinė užpakalinė programa, kurią naudosime diegdami priekinę pusę (nenagrinėsime, nes čia nėra pagrindinis dėmesys, bet kodas buvo sąmoningai paprastas, todėl jums nebus sunku su juo )

Pradedame nuo šių puslapių ir komponentų kūrimo:

  • Pagrindinis puslapis

  • Prisijungimo puslapis

  • Redaguoti vartotojo puslapį

  • Navbar komponentas

  • „UserDropdown“ komponentas

„React“ programai su keliais puslapiais reikia tinkamos naršymo, todėl galime naudoti „react-router-dom“, kad sukurtume visuotinį naršyklės maršrutizatoriaus kontekstą ir užregistruotų skirtingus „React“ maršrutus.


yarn add react-router-dom

Žinome, kad daugelis skaitytojų nori sekti ir mokytis, todėl čia yra pradinis šablonas, padėsiantis paspartinti. Ši pradinė šaka naudoja DaisyUI iš anksto nustatytiems TailwindCSS JSX komponentams. Jame yra visi komponentai, puslapiai ir jau nustatytas maršrutizatorius. Jei ketinate vadovautis šia mokymo programa ir patys sukurti visą autentifikavimo eigą, atlikdami paprastus veiksmus, pirmiausia išskirkite saugyklą. Sujungę saugyklą, klonuokite ją ir pradėkite nuo start-herefilialo:


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

Ištraukę šaką pradžia čia:

  • Atidarykite projektą naudodami pageidaujamą kodo rengyklę

  • Pakeiskite katalogą į frontend/

  • Įdiekite priklausomybes: verpalai

  • Paleiskite kūrimo serverį: yarn dev·

Peržiūra turėtų atrodyti maždaug taip:

Changing user name

Navigacijos juostoje (viršutinėje dešinėje pusėje) pateikiamas pavadinimas yra būsenos kintamasis, apibrėžtas pagrindiniame programos komponente. Tas pats kintamasis perduodamas ir naršymo juostai, ir pagrindiniam puslapiui. Aukščiau naudojama paprasta forma iš tikrųjų atnaujina būsenos kintamąjį „pavadinimas“ iš „EditPage“ komponento.

Toliau pateikiami du požiūriai, kuriuose bus išsamiai aprašyta įgyvendinimas:

Pirmasis požiūris: useState

useState()

„useState“ yra vienas iš dažniausiai naudojamų „React“ kabliukų, leidžiantis sukurti ir pakeisti būseną „React Functional“ komponente. „useState“ komponentas įgyvendinamas labai paprastai ir jį lengva naudoti: norėdami sukurti naują būseną, turite iškviesti useState su pradine būsenos reikšme, o „useState“ kabliukas grąžins masyvą, kuriame yra du kintamieji: pirmasis yra būsena. kintamasis, kurį galite naudoti norėdami nurodyti savo būseną, o antrasis – funkcija, kurią naudojate būsenos reikšmei keisti: gana paprasta.

O kaip mes tai pamatytume veikiant? Navigacijos juostoje (viršutinėje dešinėje pusėje) pateikiamas pavadinimas yra būsenos kintamasis, apibrėžtas pagrindiniame programos komponente. Tas pats kintamasis perduodamas ir naršymo juostai, ir pagrindiniam puslapiui. Aukščiau naudojama paprasta forma iš tikrųjų atnaujina būsenos kintamąjį „pavadinimas“ iš „EditPage“ komponento. Apatinė eilutė yra tokia: useState yra pagrindinis kabliukas, kuris priima pradinę būseną kaip parametrą ir grąžina du kintamuosius, turinčius dvi reikšmes, būsenos kintamąjį, kuriame yra pradinė būsena, ir to paties būsenos kintamojo nustatymo funkciją.

Išskaidykime jį ir pažiūrėkime, kaip tai buvo įgyvendinta.

  1. Būsenos kintamojo „pavadinimas“ kūrimas:

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

Rekvizitas

Rekvizitai yra vienas iš pagrindinių react komponento sudedamųjų dalių, konceptualiai, jei jūs manote, kad React funkcinis komponentas yra „Javascript“ funkcija, tada rekvizitai yra tik funkcijos parametrai, derinant rekvizitus ir „useState Hook“ gali pasiūlyti tvirtą pagrindą. būsenai valdyti naudojant paprastą „React“ programą.

React rekvizitai perduodami kaip atributai priskirtiems komponentams. Atributai, perduoti kaip rekvizitai, gali būti sunaikinti iš butaforijos objekto, priimant jį kaip argumentą, panašiai kaip:

Perdavimo rekvizitai

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

Rekvizitai gali būti priimti ir naudojami funkcinio komponento viduje, panašiai kaip įprastos funkcijos argumentai. Kadangi „pavadinimas“ perduodamas kaip pagrindinio komponento rekvizitas, galime jį pateikti tame pačiame komponente. Šiame pavyzdyje mes priimame perduotą rekvizitą, naudodami naikinimo sintaksę, kad iš objekto rekvizitai išgautume nuosavybės pavadinimą.

Rekvizito priėmimas

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

Pro patarimas

Atidarykite naršyklės konsolę ir pastebėkite, kaip visi komponentai, naudojantys „pavadinimo“ rekvizitą, iš naujo pateikiami pasikeitus būsenai. Kai manipuliuoja būsenos kintamuoju, „React“ išsaugos kitą būseną, vėl pateiks jūsų komponentą su naujomis reikšmėmis ir atnaujins vartotojo sąsają.

Components Re-rendering

naudokite būsenos trūkumus

Rekvizitas-gręžimas

Rekvizitų gręžimas yra terminas, nurodantis komponentų hierarchiją, kai komponentų rinkiniui reikia tam tikrų pagrindinio komponento teikiamų rekvizitų. Įprastas sprendimas, kurį paprastai naudoja nepatyręs kūrėjas, yra perduoti šiuos rekvizitus per visą komponentų grandinę. požiūris yra toks, kad pakeitus bet kurį iš šių rekvizitų, visa komponentų grandinė bus perteikta, o tai veiksmingai sulėtins visos programos veikimą dėl šių nereikalingų atvaizdų, grandinės viduryje esančių komponentų, kuriems nereikia šių rekvizitų. veikia kaip rekvizito perdavimo priemonės.

Pavyzdys:

– Būsenos kintamasis buvo apibrėžtas pagrindiniame programos komponente, naudojant kabliuką useState().

  • Vardo pasiūlymas buvo perduotas Navbar komponentui

  • Tas pats pasiūlymas priimtas „Navbar“ ir dar kartą perduotas „UserDropdown“ komponentui

  • UserDropdown yra paskutinis antrinis elementas, kuris priima rekvizitus.

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

Įsivaizduokite, kaip sunku išlaikyti „React“ programą su skirtingais komponentų sluoksniais, kurie perduoda ir pateikia tą pačią būseną.

Augantis sudėtingumas ir kodo kokybė

Naudojant „useState“ ir „props“ kaip vienintelę būsenos valdymo priemonę „React“ programoje, kodų bazė gali greitai tapti sudėtingesnė, nes turi valdyti dešimtis ar šimtus būsenos kintamųjų, kurie gali būti vienas kito dublikatai, išsibarstę po skirtingus failus ir komponentai gali būti gana bauginantys, bet koks tam tikro būsenos kintamojo pakeitimas turės atidžiai apsvarstyti komponentų priklausomybes, kad būtų išvengta galimo papildomo atvaizdavimo ir taip lėtoje programoje.

Antrasis metodas: konteksto API

„Context API“ yra „React“ bandymas išspręsti trūkumus, susijusius su tik rekvizitų ir useState naudojimo būsenos valdymui, ypač konteksto API yra atsakymas į anksčiau paminėtą problemą, susijusią su būtinybe perduoti rekvizitus visame komponentų medyje. Naudodami kontekstą galite apibrėžti būseną duomenims, kuriuos laikote visuotiniais, ir pasiekti jų būseną iš bet kurio komponento medžio taško: daugiau nereikia gręžti.

Svarbu pažymėti, kad kontekstinė API iš pradžių buvo sukurta siekiant išspręsti visuotinio duomenų, pvz., vartotojo sąsajos temų, autentifikavimo informacijos, kuri yra mūsų naudojimo atvejis, kalbų ir pan.), bendrinimo su kitais duomenimis, kuriais reikia bendrinti, problemą. tarp daugiau nei vieno komponento, bet nebūtinai yra globalus visai programai, kontekstas gali būti ne geriausias pasirinkimas, atsižvelgiant į naudojimo atvejį, galite apsvarstyti kitus metodus, pvz., komponento sudėtį, kuri nepatenka į šio straipsnio taikymo sritį.

Perjungimas į kontekstą

Auth konteksto kūrimas

CreateContext yra nesudėtinga, jis sukuria naują kontekstinį kintamąjį, paima vieną neprivalomą parametrą: numatytąją kontekstinio kintamojo reikšmę.

Pažiūrėkime, kaip tai veikia, pirmiausia sukurkite naują aplanką „kontekstai“ ir naują failą jame „Auth.jsx“. Norėdami sukurti naują kontekstą, turime iškviesti funkciją createContext(), grąžintą reikšmę priskirti naujam kintamajam Auth, kuris bus eksportuojamas toliau:

./src/contexts/Auth.jsx

import { createContext } from "react";

export const Auth = createContext();

Pateikite autentifikavimo kontekstą

Dabar turime atskleisti kontekstinį kintamąjį „Auth“, kurį sukūrėme anksčiau, kad tai pasiektume, naudojame konteksto teikėją, konteksto teikėjas yra komponentas, turintis „vertės“ rekvizitą, galime naudoti šį rekvizitą, kad bendrintume vertę – pavadinimą. – visame komponentų medyje, apvyniodami komponentų medį tiekėjo komponentu, tą vertę padarome pasiekiamą iš bet kurios komponento medžio vietos, nereikia perduoti to rekvizito kiekvienam antriniam komponentui atskirai.

Mūsų autentifikavimo pavyzdyje mums reikia kintamojo, kad būtų laikomas vartotojo objektas, ir tam tikro nustatymo priemonės, kad būtų galima valdyti tą būsenos kintamąjį. Tai puikus useState naudojimo atvejis. Kai naudojate kontekstą, turite įsitikinti, kad apibrėžiate duomenis, kuriuos norite pateikti, ir perduodate tuos duomenis (mūsų pavyzdyje naudotojas) į visą komponentų medį, esantį viduje, todėl teikėjo komponente apibrėžkite naują būsenos kintamąjį vartotojas ir galiausiai masyve perduodame naudotoją ir setUser kaip reikšmę, kurią teikėjas parodys komponentų medžiui:

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

Kitas dalykas, kurį galime padaryti, yra perkelti savo „pavadinimo“ būsenos kintamąjį iš pagrindinio programos komponento į autentifikavimo kontekstą ir atskleisti jį įdėtiesiems komponentams:

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

Dabar belieka mūsų programą įdėti į tą patį „AuthProvider“ komponentą, kurį ką tik eksportavome.

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

Kadangi antrinius rekvizitus pateikiame Auth.Provider viduje, visi elementai, įterpti į AuthProvider komponentą, dabar gali naudoti rekvizitus, kuriuos perdavėme Auth.Provider. Tai gali atrodyti painu, bet kai su juo paeksperimentuosite, pabandykite pateikti ir naudoti globalią – konteksto – būseną. Galų gale, tai man pasirodė prasminga tik eksperimentavus su konteksto API.

Auth konteksto naudojimas

Paskutinis veiksmas yra nesudėtingas, mes naudojame konteksto kabliuką „useContext“, kad pasiektume reikšmę, kurią teikia konteksto „Auth“ teikėjas, o tai mūsų atveju yra masyvas, kuriame yra user ir setUser, kitame kode galime naudokite useContext, kad naudotumėte autentifikavimo kontekstą naršymo juostoje. Tai įmanoma tik todėl, kad „Navbar“ yra įdėta programos komponento viduje, o „AuthProvider“ apgaubia programos komponentą, todėl vertės pasiūlymas gali būti naudojamas tik naudojant „useContext“ kabliuką. Kitas puikus „React“ įrankis, skirtas valdyti bet kokius duomenis, kuriuos gali pasiekti visame pasaulyje ir kuriuos gali valdyti bet kuris vartotojo komponentas.

./src/components/Navbar.jsx

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

 return (...)};

Atkreipkite dėmesį, kaip „Navbar“ () funkciniame komponente nebepriimame jokių rekvizitų. Auth kontekstui naudoti naudojame useContext(Auth), paimdami ir pavadinimą, ir setName. Tai taip pat reiškia, kad mums nebereikia perduoti rekvizito Navbar:

./src/App.jsx

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

Auth konteksto atnaujinimas

Taip pat galime naudoti pateiktą funkciją setName, kad galėtume valdyti būsenos kintamąjį „name“:

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

Pristatome useReducer() kabliuką

Ankstesniame pavyzdyje naudojome kontekstinę API, norėdami valdyti ir bendrinti savo būseną komponentų medyje. Galbūt pastebėjote, kad vis dar naudojame „useState“ kaip savo logikos pagrindą, ir tai dažniausiai yra gerai, nes mūsų būsena vis dar yra paprastas objektas. šiuo metu, bet jei norėtume išplėsti savo autentifikavimo srauto galimybes, tikrai turėsime saugoti ne tik šiuo metu prisijungusio vartotojo el. pašto adresą, todėl grįžtame prie anksčiau nustatytų apribojimų, susijusių su Laimei, „useState“ naudojimas su sudėtinga būsena, laimei, „React“ išsprendžia šią problemą suteikdama alternatyvą „useState“ sudėtingai būsenai valdyti: įveskite „useReducer“.

„useReducer“ gali būti laikomas apibendrinta „useState“ versija, jai reikalingi du parametrai: reduktorius ir pradinė būsena.

Nieko įdomaus pastebėti dėl pradinės būsenos, magija vyksta reduktoriaus funkcijoje: ji patikrina įvykusio veiksmo tipą ir, priklausomai nuo to veiksmo, reduktorius nustatys, kokius atnaujinimus taikyti būsenai ir grąžins naują vertę. .

Žvelgiant į toliau pateiktą kodą, reduktoriaus funkcija gali būti dviejų tipų:

  • PRISIJUNGTI“: tokiu atveju vartotojo būsena bus atnaujinta naujais vartotojo kredencialais, pateiktais veiksmo apkrovoje.

  • Atsijungti“: tokiu atveju naudotojo būsena bus pašalinta iš vietinės saugyklos ir grąžinama į nulinę.

Svarbu pažymėti, kad veiksmo objekte yra ir tipo laukas, nurodantis, kokią logiką taikyti, ir pasirenkamas naudingosios apkrovos laukas, kad būtų pateikti duomenys, reikalingi tai logikai taikyti.

Galiausiai „useReducer“ kabliukas grąžina dabartinę būseną ir siuntimo funkciją, kurią naudojame veiksmui perduoti reduktoriui.

Kalbant apie likusią logikos dalį, tai identiška ankstesniame pavyzdyje:

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

Veiksmų siuntimas vietoj funkcijos setState nustatymo – pvz.: setName –

Kaip ką tik minėjome, mes naudojame išsiuntimo funkciją norėdami perduoti veiksmą reduktoriui, sekančiame kode inicijuojame LOGIN veiksmą ir pateikiame vartotojo el. pašto adresą kaip naudingą apkrovą, dabar vartotojo būsena bus atnaujinta ir šis pakeitimas suaktyvins visų komponentų, prenumeruotų vartotojo būsenoje, pakartotinis pateikimas. Svarbu pažymėti, kad pakartotinis atvaizdavimas bus suaktyvintas tik tuo atveju, jei įvyks faktinis būsenos pasikeitimas, o pakartotinis pateikimas nebus atliktas, jei reduktorius grąžins tą pačią ankstesnę būseną.

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

Vartotojo prisijungimas

JWT Local storage

Pro patarimas

Atkreipkite dėmesį, kaip vartotojo objektas, kurį gauname po sėkmingo prisijungimo, dabar yra saugomas vietinėje saugykloje.

Pasirinktinis prisijungimo kabliukas

Dabar, kai gerai valdome „useReducer“, galime toliau įtraukti savo prisijungimo ir atsijungimo logiką į atskirus pasirinktinius kabliukus, vienu iškvietimu į prisijungimo kabliuką, galime apdoroti API iškvietimą į prisijungimo maršrutą, atkurti naują vartotoją. kredencialus ir saugokite juos vietinėje saugykloje, išsiųskite LOGIN skambutį, kad atnaujintumėte vartotojo būseną, kartu tvarkydami klaidas:

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

Pastaba: patyrusiems „React“ naudotojams tarp skaitytojų gali kilti klausimas, kodėl nepasinaudojome tingios „useReducer“ inicijavimo funkcijos, kad gautume vartotojo kredencialus, „useReducer“ priima trečią pasirenkamą parametrą, vadinamą „init“ funkcija. Ši funkcija naudojama tuo atveju, Turime pritaikyti tam tikrą logiką, kad galėtume gauti pradinę būsenos vertę, priežastis, kodėl to nepasirinkome, yra paprastas problemų atskyrimo klausimas, kodą tokiu būdu lengviau suprasti ir dėl to lengviau prižiūrėti .

Prisijungimo puslapis

Štai kaip atrodo viršutinė mūsų prisijungimo puslapio dalis, naudojant kabliuką useLogin() prisijungimo funkcijai išgauti ir iškvietus prisijungimo funkciją su vartotojo pateiktais kredencialais:

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

Taip pat išjungiame funkciją Pateikti, kai vartotojas pateikia formą:

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

Ir pateikiant visas autentifikavimo klaidas, kurias gauname iš mūsų užpakalinės programos:

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

Rendering Errors

Vartotojo būsenos palaikymas

Jums gali kilti klausimas, kodėl mums reikia saugoti vartotojo objektą vietinėje saugykloje, paprasčiausiai tariant, norime, kad vartotojas būtų prisijungęs tol, kol nepasibaigęs prieigos raktas. „LocalStorage“ naudojimas yra puikus būdas saugoti JSON bitus, kaip ir mūsų pavyzdyje. Atkreipkite dėmesį, kaip būsena ištrinama, jei prisijungę atnaujinate puslapį. Tai galima lengvai išspręsti naudojant useEffect kabliuką, kad patikrintumėte, ar turime saugomą vartotojo objektą „localStorage“, jei toks yra, prisijungiame automatiškai:

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

Pasirinktiniai kabliukai atsijungimui

Tas pats pasakytina ir apie atsijungimo kabliuką, čia mes siunčiame LOGOUT veiksmą, kad pašalintume esamus vartotojo kredencialus ir iš būsenos, ir iš vietinės saugyklos:

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

Vartotojo atsijungimas

Norėdami atsijungti nuo vartotojo, pridėkime paspaudimo įvykį prie mygtuko Atsijungti, esančio UserDropdown.jsx, ir atitinkamai tvarkykime:

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

Reagavimo maršrutų apsauga

Paskutinis mūsų programos diegimo veiksmas yra panaudoti visuotinę vartotojo būseną, kad būtų galima valdyti vartotojo naršymą, greitas priminimas apie tai, kokio elgesio turėtume pasiekti: iš pradžių vartotoją pasitinka prisijungimo puslapis, nuo to momento vartotojas gali pasiekti tik pagrindinį puslapį. po sėkmingo prisijungimo vartotojas atsijungus bus nukreiptas į prisijungimo puslapį.

Tai pasiekiame naudodami react-router-dom biblioteką, apibrėždami 2 maršrutus: „/“ ir „/login“, valdome, kurį komponentą pateikti kiekviename maršrute, naudodami visuotinę autentifikavimo būseną., autentifikavimo įvertinimas į null reiškia neautentifikuotą vartotoją ir atvirkščiai:

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

Apibendrinimo diagrama

Diagram

Užbaigimas

Šiame straipsnyje mes bandėme išnagrinėti paprastą, bet labai įprastą autentifikavimo darbo eigos būsenos valdymo diegimo atvejį, apžvelgdami skirtingus metodus, kiekvieno iš jų pagrindimą ir jų kompromisus. Būsenos valdymas kliento sistemose ir ypač „React“ yra viena iš labiausiai aptariamų temų frontend bendruomenėje vien todėl, kad jis gali pagerinti arba sutrikdyti jūsų programos našumą ir mastelį. Didžiulis įvairių metodų, modelių, bibliotekų ir įrankių, kuriais bandoma išspręsti šią valstybės valdymo problemą, skaičius yra didžiulis, mūsų tikslas buvo suteikti jums gerą supratimą apie praktiką, kad galėtumėte ją įdiegti savo programoje, kad galėtumėte pažengti į priekį. Būsenos valdymo metodus ir modelius sudėtingesnėse programose, peržiūrėkite kitą mūsų straipsnį, kuriame apžvelgsime „React“ keičiamo būsenos valdymo redux.

Netrukus

ContextAPI vs Redux Toolkit

„Redux“ bendruomenėje buvo naudojamas daugelį metų prieš „Redux“ įrankių rinkinį, iš tikrųjų RTK buvo pristatytas kaip pradinis šablonas, skirtas redux būsenos valdymui paleisti naujose programose (jo pradinis pavadinimas buvo „redux-starter-kit“ 2019 m. spalio mėn.), nors Šiandien „Redux“ prižiūrėtojai ir bendruomenė sutaria, kad „Redux“ įrankių rinkinys yra tinkamas būdas dirbti su redux. RTX ištraukia daug „Redux“ logikos, todėl ją lengviau naudoti, kur kas mažiau žodžių, ir skatina kūrėjus Vadovaukitės geriausios praktikos pavyzdžiais, vienas iš pagrindinių skirtumų tarp šių dviejų yra tas, kad „Redux“ buvo sukurtas taip, kad nebūtų nuomonių, suteikiant minimalią API ir tikimasi, kad kūrėjai atliks didžiąją dalį sunkaus darbo, rašydami savo bibliotekas įprastoms užduotims atlikti ir tvarkydami kodo struktūrą, Dėl to sulėtėjo kūrimo laikas ir netvarkingas kodas, „Redux“ įrankių rinkinys buvo pridėtas kaip papildomas abstrakcijos sluoksnis, neleidžiantis kūrėjams patekti į įprastas spąstus. Daugiau įžvalgų ir prižiūrėtojų argumentų rasite oficialioje dokumentacijoje čia.


Career Services background pattern

Karjeros paslaugos

Contact Section background image

Palaikykime ryšį

Code Labs Academy © 2024 Visos teisės saugomos.