Staatsbestuur in reaksie: 'n Praktiese voorbeeld

reageer
staatsbestuur
konteks-API
Staatsbestuur in reaksie: 'n Praktiese voorbeeld cover image

React is die beste raamwerk vir die bou van dinamiese toepassings aan die kliëntkant vir baie ontwikkelaars. Die dinamiese aard van hierdie toepassings kom van die buigsaamheid en die uitgebreide lys van vermoëns en kenmerke wat moontlik is aan die kliëntkant wat ontwikkelaars in staat gestel het om volwaardige toepassings te bou wat binne 'n kwessie van sekondes op die blaaier laai, 'n prestasie wat nie was nie. moontlik (of baie omslagtig) in die dae van die statiese web.

Met hierdie uitbreiding in moontlikhede het die konsep van staatsbestuur gekom, namate kompleksiteit in kliëntkanttoepassings toeneem, groei die behoefte om plaaslike staat te behou om 'n bottelnek op sigself te word as dit nie korrek hanteer word en met skaalbaarheid in gedagte uitgedink word nie.

Hierdie kwessie is aangespreek deur baie raamwerke, wat verskillende benaderings volg en op verskillende stelle subprobleme gefokus het, daarom is dit belangrik om 'n hoëvlakbegrip van die ekosisteem van die raamwerk van keuse te hê om elke toepassing se behoeftes te assesseer en die regte benadering te volg volgens die metrieke. Hierdie artikel sal jou 'n kort oorsig gee van die algemene staatsbestuurskwessies en probeer om verskillende benaderings (useState, Context API) in te voer as 'n reaksie daarop. Alhoewel hierdie artikel verskeie oplossings sal bied, sal dit slegs op uitdagings op 'n kleiner skaal fokus, ons sal meer gevorderde onderwerpe in komende artikels dek.

Verifikasie werkvloei

Die kode wat regdeur die artikel vertoon word, kan hier gevind word.

'n Regstreekse voorskouskakel kan verkry word hier.

Oorweeg die geval waar ons die stawingsproses vir 'n React-toepassing implementeer.

User Login

Soos in die GIF hierbo getoon, wil ons gebruikers toelaat om aan te meld of by ons toepassing aan te meld deur geloofsbriewe te gebruik. As geldige geloofsbriewe verskaf is, sal die gebruiker aangemeld word, die toepassing sal outomaties na die tuisblad navigeer en die gebruiker kan voortgaan om die toepassing te gebruik.

Net so, as die gebruiker uitteken, sal die tuisbladhulpbronne agter aanmelding beskerm word, die aanmeldbladsy sal die enigste bladsy wees wat deur die gebruiker toeganklik is.

As ons aan hierdie werkvloei in terme van implementering dink, sal ons 'n hoofkomponent genaamd Toepassing hê, die Toepassingskomponent sal die gebruiker na een van twee bladsye herlei: Tuis of Aanmelding, die huidige toestand van gebruiker (aangemeld, afgemeld) sal bepaal watter bladsy waarna die gebruiker herlei word, moet 'n verandering in die huidige toestand van die gebruiker (byvoorbeeld verandering van aangemeld na afgemeld) 'n onmiddellike herleiding na die ooreenstemmende bladsy veroorsaak.

State

Soos in die illustrasie hierbo getoon, wil ons hê dat die App-komponent die huidige toestand moet oorweeg en slegs een van die twee bladsye – Tuis of Aanmelding – moet weergee op grond van daardie huidige toestand.

As die gebruiker nul is, beteken dit dat ons nie 'n geverifieerde gebruiker het nie, so ons navigeer outomaties na die aanmeldbladsy en beskerm die tuisblad met behulp van voorwaardelike lewering. As die gebruiker bestaan, doen ons die teenoorgestelde.

Noudat ons 'n goeie begrip het van wat geïmplementeer moet word, kom ons ondersoek 'n paar opsies, maar laat ons eers ons React-projek opstel,

Die projek repo bevat 'n voorbeeld backend-toepassing wat ons sal gebruik om die frontend-kant te implementeer (ons sal nie daarop ingaan nie, aangesien dit nie die hooffokus hier is nie, maar die kode is doelbewus eenvoudig gehou sodat jy nie 'n moeilike tyd daarmee sal hê nie )

Ons begin deur die volgende bladsye en komponente te skep:

  • Tuisblad

  • Aanteken bladsy

  • Wysig gebruikerbladsy

  • Navbar-komponent

  • Gebruiker-aflaai-komponent

'n React-toepassing met veelvuldige bladsye benodig behoorlike navigasie, daarvoor kan ons die react-router-dom gebruik om 'n globale blaaier-router-konteks te skep en verskillende React-roetes te registreer.


yarn add react-router-dom

Ons weet baie lesers verkies om saam met tutoriale te volg, so hier is die beginsjabloon om jou op hoogte te bring. Hierdie beginnertak gebruik DaisyUI vir vooraf gedefinieerde TailwindCSS JSX-komponente. Dit bevat alle komponente, bladsye en die router wat reeds opgestel is. As jy dit oorweeg om saam met hierdie tutoriaal te volg, bou die hele magtigingsvloei self deur eenvoudige stappe te volg, begin deur eers die bewaarplek te vurk. Nadat jy die bewaarplek gevurk het, kloon dit en begin vanaf die begin-hiertak:


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

Sodra jy die begin-hier-tak trek:

  • Maak die projek oop met jou voorkeurkode-redigeerder

  • Verander gids na frontend/

  • Installeer afhanklikhede: gare

  • Begin 'n ontwikkelingsbediener: yarn dev·

Die voorskou behoort so iets te lyk:

Changing user name

Die naam wat in die navigasiebalk weergegee word - regs bo - is 'n toestandsveranderlike wat in die hooftoepassingskomponent gedefinieer word. Dieselfde veranderlike word na beide Navbar en Tuisblad oorgedra. Die eenvoudige vorm wat hierbo gebruik word, werk eintlik die "naam"-toestandsveranderlike op vanaf die EditPage-komponent.

Die twee benaderings wat hieronder aangebied word, sal ingaan op die besonderhede van implementering:

Eerste benadering: useState

useState()

useState is een van die mees gebruikte React-hake, dit laat jou toe om toestand in 'n React Functional-komponent te skep en te muteer. Die useState-komponent het 'n baie eenvoudige implementering en is maklik om te gebruik: om 'n nuwe toestand te skep, moet jy useState noem met die aanvanklike waarde van jou toestand en die useState-haak sal 'n skikking terugstuur wat twee veranderlikes bevat: die eerste een is die toestand veranderlike wat jy kan gebruik om jou toestand te verwys, en die tweede een 'n funksie wat jy gebruik om die waarde van die staat te verander: redelik eenvoudig.

Hoe gaan ons dit in aksie sien? Die naam wat in die navigasiebalk weergegee word - regs bo - is 'n toestandsveranderlike wat in die hooftoepassingskomponent gedefinieer word. Dieselfde veranderlike word na beide Navbar en Tuisblad oorgedra. Die eenvoudige vorm wat hierbo gebruik word, werk eintlik die "naam"-toestandsveranderlike op vanaf die EditPage-komponent. Bottom line is dit: useState is 'n kernhaak wat 'n aanvanklike toestand as 'n parameter aanvaar en twee veranderlikes met twee waardes terugstuur, die toestandsveranderlike wat die aanvanklike toestand bevat, en 'n stelfunksie vir dieselfde toestandsveranderlike.

Kom ons breek dit af en kyk hoe dit in die eerste plek geïmplementeer is.

  1. Die skep van die "naam"-staatsveranderlike:

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

Rekwisiete

Rekwisiete is een van die basiese boustene van 'n reageer-komponent, konseptueel, as jy aan 'n React-funksionele komponent dink as 'n Javascript-funksie, dan is rekwisiete nie meer as die funksieparameters nie, die kombinasie van rekwisiete en die useState-haak kan jou 'n soliede raamwerk bied vir die bestuur van toestand oor 'n eenvoudige React-toepassing.

Reageerstutte word as kenmerke aan pasgemaakte komponente oorgedra. Eienskappe wat as rekwisiete oorgedra word, kan van die rekwisietevoorwerp gedestruktureer word wanneer dit as 'n argument aanvaar word, soortgelyk aan hierdie:

verbygaande rekwisiete

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

Rekwisiete kan aanvaar en gebruik word binne 'n funksionele komponent soortgelyk aan normale funksie argumente. Dit is omdat "naam" as 'n stut aan die Tuis-komponent oorgedra word, dat ons dit in dieselfde komponent kan weergee. In die volgende voorbeeld aanvaar ons die geslaagde stut deur die destruktureringssintaksis te gebruik om die naam-eienskap uit die props-objek te onttrek.

Aanvaarding van rekwisiete

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

Maak die blaaier se konsole oop en let op hoe alle komponente wat die "naam"-stut gebruik, weer vertoon wanneer die toestand verander. Wanneer 'n toestandsveranderlike gemanipuleer word, sal React die volgende toestand stoor, jou komponent weer met die nuwe waardes weergee en die UI opdateer.

Components Re-rendering

gebruik Staat Nadele

stutte-boor

Props drilling is 'n term wat verwys na 'n hiërargie van komponente waar 'n stel komponente sekere stutte benodig wat deur 'n ouer komponent verskaf word, 'n algemene oplossing wat onervare ontwikkelaar gewoonlik gebruik is om hierdie stutte deur die hele ketting van komponente te laat slaag, die probleem met hierdie benadering is dat 'n verandering in enige van hierdie rekwisiete die hele ketting van komponente sal aktiveer om weer te gee, wat die hele toepassing effektief sal vertraag as gevolg van hierdie onnodige lewerings, die komponente in die middel van die ketting wat nie hierdie stutte benodig nie. dien as medium vir die oordrag van rekwisiete.

Voorbeeld:

  • 'n Toestandsveranderlike is in die hooftoepassingskomponent gedefinieer deur gebruik te maak van die useState()-haak

  • 'n Naamstut is na die Navbar-komponent oorgedra

  • Dieselfde stut is in Navbar aanvaar en weer as stut oorgedra na UserDropdown-komponent

  • UserDropdown is die laaste kinderelement wat die rekwisiet aanvaar.

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

Stel jou voor hoe moeilik dit is om 'n React-toepassing in stand te hou met verskillende lae komponente wat almal deurgaan en dieselfde toestand weergee.

Groeiende kompleksiteit en kodekwaliteit

Met die gebruik van useState en rekwisiete as die enigste manier van staatsbestuur in 'n reageertoepassing, kan die kodebasis vinnig in kompleksiteit groei, deur tien of honderde staatsveranderlikes te bestuur, wat duplikate van mekaar kan wees, versprei oor verskillende lêers en komponente kan nogal skrikwekkend wees, enige verandering aan 'n gegewe toestandsveranderlike sal noukeurige oorweging van afhanklikhede tussen komponente vereis om enige potensiële bykomende herlewering in 'n reeds stadige toepassing te vermy.

Tweede benadering: konteks-API

Die Konteks-API is React se poging om die nadele van die gebruik van rekwisiete en useState vir staatsbestuur op te los, veral die konteks-API kom as 'n antwoord op die kwessie wat voorheen genoem is rakende die behoefte om rekwisiete deur die hele komponentboom deur te gee. Met die gebruik van konteks kan jy 'n toestand definieer vir data wat jy as globaal beskou en toegang tot die toestand daarvan kry vanaf enige punt in die komponentboom: nie meer stutboor nie.

Dit is belangrik om daarop te wys dat die konteks-API aanvanklik ontwerp is om die kwessie van globale datadeling, data soos UI-temas, verifikasie-inligting wat ons gebruiksgeval is, tale en so iets op te los vir ander tipes data wat gedeel moet word tussen meer as een komponent maar is nie noodwendig globaal vir al die toepassings nie, konteks is dalk nie die beste opsie nie, afhangende van die gebruiksgeval, kan jy ander tegnieke oorweeg soos komponentsamestelling wat buite die bestek van hierdie artikel val.

Skakel oor na konteks

Skep die Auth-konteks

createContext is eenvoudig, dit skep 'n nuwe konteksveranderlike, dit neem 'n enkele opsionele parameter in: die verstekwaarde van die konteksveranderlike.

Kom ons sien dit in aksie, skep eers 'n nuwe vouer "contexts" en 'n nuwe lêer binne-in dit "Auth.jsx". Om 'n nuwe konteks te skep, moet ons die createContext() funksie aanroep, die teruggekeerde waarde toeken aan 'n nuwe veranderlike Auth wat volgende uitgevoer sal word:

./src/contexts/Auth.jsx

import { createContext } from "react";

export const Auth = createContext();

Verskaf die Auth-konteks

Nou moet ons die "Auth" konteksveranderlike wat ons voorheen geskep het blootlê, om dit te bereik gebruik ons ​​die konteksverskaffer, die konteksverskaffer is 'n komponent wat 'n "waarde" stut het, ons kan hierdie stut gebruik om 'n waarde – naam te deel – oor die komponentboom, deur die komponentboom met die verskafferkomponent te draai, maak ons ​​daardie waarde toeganklik vanaf enige plek binne die komponentboom, sonder dat dit nodig is om daardie stut aan elke kindkomponent individueel deur te gee.

In ons verifikasievoorbeeld het ons 'n veranderlike nodig om die gebruikervoorwerp te hou, en 'n soort opsteller om daardie toestandsveranderlike te manipuleer, dit is 'n perfekte gebruiksgeval vir useState. Wanneer jy Konteks gebruik, moet jy seker maak jy definieer die data wat jy wil verskaf, en gee daardie data – gebruiker in ons voorbeeld – aan al die komponentboom wat binne geneste is, so definieer 'n nuwe toestandsveranderlike gebruiker binne die verskafferkomponent en uiteindelik gee ons beide gebruiker en setUser binne 'n skikking deur as die waarde wat die verskaffer aan die komponentboom sal blootstel:

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

Nog 'n ding wat ons kan doen, is om ons "naam"-toestandveranderlike van die hoofprogramkomponent na die Auth-konteks te skuif en dit aan geneste komponente bloot te stel:

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

Nou is al wat oorbly, om ons toepassing in dieselfde AuthProvider-komponent te nes wat ons sopas uitgevoer het.

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

Omdat ons die kinderstut binne Auth.Provider weergee, kan alle elemente wat binne die AuthProvider-komponent geneste is, nou die waardestut wat ons aan Auth.Provider oorgedra het, verbruik. Dit mag dalk verwarrend lyk, maar sodra jy daarmee eksperimenteer, probeer om 'n globale - Konteks - toestand te verskaf en te verbruik. Dit het immers eers vir my sin gemaak nadat ek met die Context API geëksperimenteer het.

Gebruik van die Auth-konteks

Die laaste stap is eenvoudig, ons gebruik die kontekshaak "useContext" om toegang te verkry tot die waarde wat die konteksverskaffer van "Auth" verskaf, wat in ons geval die skikking is wat gebruiker en setUser bevat, in die volgende kode kan ons gebruik useContext om die Auth-konteks binne die Navbar te gebruik. Dit is slegs moontlik omdat Navbar binne-in die App-komponent geneste is, en aangesien AuthProvider om die App-komponent draai, kan die waardestut verbruik word deur slegs die useContext-haak te gebruik. Nog 'n wonderlike hulpmiddel wat React uit die boks bied om enige data te bestuur wat wêreldwyd toegang kan kry en ook deur enige verbruikerskomponent gemanipuleer kan word.

./src/components/Navbar.jsx

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

 return (...)};

Let op hoe ons geen rekwisiete meer in die Navbar() funksionele komponent aanvaar nie. Ons gebruik useContext(Auth) om eerder die Auth-konteks te gebruik, en gryp beide naam en setName. Dit beteken ook dat ons nie meer die stut na Navbar hoef deur te gee nie:

./src/App.jsx

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

Opdatering van die Auth-konteks

Ons kan ook die verskafde setName-funksie gebruik om die "name"-toestandsveranderlike te manipuleer:

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

Stel gebruikReducer()-haak bekend

In die vorige voorbeeld het ons die konteks-API gebruik om ons toestand in die komponentboom te bestuur en te deel, jy het dalk opgemerk dat ons steeds useState as die basis van ons logika gebruik, en dit is meestal ok aangesien ons toestand steeds 'n eenvoudige voorwerp is op hierdie stadium, maar as ons die vermoëns van ons verifikasievloei sou uitbrei, sal ons beslis meer moet stoor as net die e-pos van die gebruiker wat tans aangemeld is, en dit is waar ons terugkeer na die beperkings wat ons voorheen ingegaan het ten opsigte van die gebruik van useState met komplekse toestand, gelukkig, React los hierdie probleem op deur 'n alternatief vir useState te verskaf vir die bestuur van komplekse toestand: voer gebruikReducer in.

useReducer kan beskou word as 'n algemene weergawe van useState, dit neem twee parameters: 'n verkleinerfunksie en 'n aanvanklike toestand.

Niks interessant om op te let vir die aanvanklike toestand nie, die magie gebeur binne die verkleinerfunksie: dit kyk na die tipe aksie wat plaasgevind het, en afhangende van daardie aksie, sal die verkleiner bepaal watter opdaterings op die staat toegepas moet word en die nuwe waarde daarvan terugstuur. .

As u na die kode hieronder kyk, het die verkleinerfunksie twee moontlike aksietipes:

  • "LOGIN": in welke geval die gebruikerstatus opgedateer sal word met die nuwe gebruikersbewyse wat binne die aksieloonvrag verskaf word.

  • "LOGOUT": in welke geval die gebruikerstatus van die plaaslike berging verwyder sal word en teruggestel word na null.

Dit is belangrik om daarop te let dat die aksie-objek beide 'n tipe veld bevat wat bepaal watter logika om toe te pas en 'n opsionele loonvragveld om data te verskaf wat nodig is vir die toepassing van daardie logika.

Laastens gee die useReducer-haak die huidige toestand en 'n versendingsfunksie terug wat ons gebruik om 'n aksie na die verkleiner deur te gee.

Vir die res van die logika is dit identies aan die vorige voorbeeld:

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

Versending van aksies in plaas daarvan om die setState-insteller-funksie te gebruik – bv: setName –

Soos ons sopas genoem het, gebruik ons ​​die versendingsfunksie om 'n aksie na die verkleiner deur te gee, in die volgende kode begin ons 'n LOGIN-aksie en ons verskaf die gebruiker-e-pos as 'n loonvrag, nou sal die gebruikerstatus opgedateer word en hierdie verandering sal aktiveer 'n herweergawe van alle komponente wat op die gebruikerstaat ingeteken is. Dit is belangrik om daarop te wys dat 'n herlewering slegs geaktiveer sal word as 'n werklike verandering in die toestand plaasvind, geen herlewerings as die verkleiner dieselfde vorige toestand terugstuur nie.

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

Gebruikersaanmelding

JWT Local storage

Pro Wenk

Let op hoe die gebruikerobjek wat ons ontvang na 'n suksesvolle aanmelding nou in die localStorage gestoor word.

Pasgemaakte haak vir aanmelding

Noudat ons 'n goeie greep op useReducer het, kan ons ons aanmeld- en afmeldlogika verder insluit in hul eie afsonderlike pasgemaakte hakies, deur 'n enkele oproep na die aanmeldhaak, kan ons 'n API-oproep na die aanmeldroete hanteer, die nuwe gebruiker herwin geloofsbriewe en stoor dit in die plaaslike berging, stuur 'n LOGIN-oproep om die gebruikerstatus op te dateer, alles terwyl u fouthantering hanteer:

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

Let wel: vir meer gevorderde React-gebruikers onder die lesers, wonder jy dalk hoekom het ons nie die lui inisialiseringsfunksie van useReducer gebruik om die gebruikersbewyse te herwin nie, useReducer aanvaar 'n derde opsionele parameter wat 'n init-funksie genoem word, hierdie funksie word gebruik in geval ons moet 'n bietjie logika toepas voordat ons die aanvanklike waarde van die staat kan kry, die rede waarom ons nie hiervoor gekies het nie, is 'n eenvoudige kwessie van skeiding van bekommernisse, die kode op hierdie manier is eenvoudiger om te verstaan ​​en as gevolg daarvan makliker om te onderhou .

Aantekenbladsy

Hier is hoe die boonste deel van ons aanmeldbladsy lyk nadat u die useLogin()-haak gebruik het om die aanmeldfunksie te onttrek, en die aanmeldfunksie opgeroep het met geloofsbriewe wat deur 'n gebruiker ingedien is:

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

Ons deaktiveer ook die Indien-funksie wanneer die gebruiker die vorm indien:

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

En die lewering van enige stawingsfoute wat ons van ons backend ontvang:

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

Rendering Errors

Die handhawing van die gebruikerstatus

Jy wonder dalk hoekom ons die gebruikervoorwerp in die localStorage moet stoor, eenvoudig gestel, ons wil die gebruiker aangemeld hou solank die teken nie verval het nie. Die gebruik van localStorage is 'n wonderlike manier om stukkies JSON te stoor, net soos in ons voorbeeld. Let op hoe die staat uitgewis word as jy die bladsy verfris nadat jy aangemeld het. Dit kan maklik opgelos word deur 'n useEffect-haak te gebruik om te kyk of ons 'n gestoorde gebruikerobjek in localStorage het, as daar een is, meld ons die gebruiker outomaties aan:

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

Pasgemaakte hake vir afmeld

Dieselfde ding geld met die uitteken-haak, hier stuur ons 'n UITLOG-aksie om die huidige gebruikersbewyse van beide die staat en die plaaslike berging te verwyder:

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

Gebruiker Logout

Om 'n gebruiker af te meld, kom ons voeg 'n klikgebeurtenis by die Logout-knoppie wat in UserDropdown.jsx gevind word, en hanteer dit dienooreenkomstig:

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

Beskerming van reaksieroetes

Die laaste stap in die implementering van ons toepassing is om die globale gebruikerstatus te benut om gebruikersnavigasie te beheer, 'n vinnige herinnering oor watter gedrag ons moet bereik: aanvanklik word die gebruiker begroet deur die aanmeldbladsy, vanaf daardie punt kan die gebruiker slegs toegang tot die tuisblad verkry. na 'n suksesvolle aanmelding, sal die gebruiker eweneens na die aanmeldbladsy herlei word by 'n afmelding.

Ons bereik dit met behulp van die react-router-dom-biblioteek deur 2 roetes te definieer: "/" en "/login", ons beheer watter komponent om by elke roete weer te gee met behulp van die globale outoriteitstaat, authentiek evalueer na null verteenwoordig 'n ongeverifieerde gebruiker en omgekeerd:

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

Herhalingsdiagram

Diagram

Afsluiting

In hierdie artikel het ons probeer om die eenvoudige maar baie algemene gebruiksgeval van die implementering van staatsbestuur vir 'n verifikasie-werkvloei aan te pak, deur die verskillende benaderings, die rasionaal agter elkeen en hul afwykings deur te gaan. Staatsbestuur in kliëntkantraamwerke en in React in die besonder is een van die onderwerpe wat die meeste in die frontend-gemeenskap bespreek word, bloot omdat dit die prestasie en die skaalbaarheid van jou toepassing kan maak of breek. Die groot hoeveelheid van die verskillende tegnieke, patrone, biblioteke en gereedskap wat probeer om hierdie kwessie van staatsbestuur op te los is oorweldigend, ons doel was om jou 'n goeie begrip van die praktyke te gee sodat jy dit in jou eie toepassing kan implementeer, vir meer gevorderde tegnieke en patrone van staatsbestuur in meer komplekse toepassings, kyk na ons volgende artikel waar ons ingaan op redux vir skaalbare staatsbestuur in React.

Kom binnekort

ContextAPI vs Redux Toolkit

Redux het baie jare van aanvaarding in die gemeenskap gehad voordat die Redux-nutsmiddelstel, in werklikheid, RTK is bekendgestel as 'n beginsjabloon om redux-staatbestuur in nuwe toepassings op te laai (sy aanvanklike naam was "redux-starter-kit" in Oktober 2019), hoewel vandag is daar 'n algemene konsensus tussen die Redux-onderhouers en die gemeenskap dat Redux-gereedskapstel die geldige manier is om met redux te werk. die beste praktyke volg, een hoofverskil tussen die twee is dat Redux gebou is om meningsloos te wees, wat 'n minimale API bied en verwag dat ontwikkelaars die meeste van die swaar opheffing sal doen deur hul eie biblioteke vir algemene take te skryf en die kodestruktuur te hanteer, dit het gelei tot stadige ontwikkelingstyd en morsige kode, Redux toolkit is bygevoeg as 'n ekstra laag van abstraksie wat verhoed dat ontwikkelaars in sy algemene slaggate val, verwys na die amptelike dokumentasie vir meer insigte en die redenasie van sy instandhouers hier.


Career Services background pattern

Loopbaandienste

Contact Section background image

Kom ons bly in kontak

Code Labs Academy © 2024 Alle regte voorbehou.