Xestión do Estado en React: un exemplo práctico

reaccionar
xestión do estado
api de contexto
Xestión do Estado en React: un exemplo práctico cover image

React é o marco de referencia para crear aplicacións dinámicas no lado do cliente para moitos desenvolvedores. A natureza dinámica destas aplicacións vén da flexibilidade e da lista estendida de capacidades e funcións que son posibles no lado do cliente, que permitiu aos desenvolvedores crear aplicacións completas que se cargasen no navegador en cuestión de segundos, unha fazaña que non era. posible (ou moi engorroso) nos tempos da web estática.

Con esta expansión das posibilidades, xurdiu o concepto de xestión do estado, a medida que a complexidade crece nas aplicacións do cliente, a necesidade de manter o estado local crece ata converterse nun pescozo de botella en si mesmo se non se manexa correctamente e se concibe pensando na escalabilidade.

Este problema foi abordado por moitos marcos, seguindo enfoques diferentes e centrándose en diferentes conxuntos de subproblemas, é por iso que é importante ter un alto nivel de comprensión do ecosistema do marco elixido para avaliar as necesidades de cada aplicación e empregar o enfoque correcto seguindo estes. métricas. Este artigo ofreceralle unha breve visión xeral dos problemas comúns de xestión do estado e tentará introducir diferentes enfoques (useState, Context API) como resposta a iso. Aínda que este artigo presentará varias solucións, só se centrará en desafíos a menor escala, trataremos temas máis avanzados nos próximos artigos.

Fluxo de traballo de autenticación

O código mostrado ao longo do artigo pódese atopar aquí.

Pódese acceder a unha ligazón de vista previa en directo aquí.

Considere o caso no que implementamos o proceso de autenticación para unha aplicación React.

User Login

Como se mostra no GIF anterior, queremos permitir aos usuarios iniciar sesión ou rexistrarse na nosa aplicación usando as credenciais. Se se proporcionaron credenciais válidas, o usuario iniciarase sesión, a aplicación navegará automaticamente ata a páxina de inicio e o usuario poderá continuar a usar a aplicación.

Do mesmo xeito, se o usuario pecha sesión, os recursos da páxina de inicio estarán protexidos tras o inicio de sesión, a páxina de inicio de sesión será a única páxina accesible polo usuario.

Pensando neste fluxo de traballo en termos de implementación, teriamos un compoñente principal chamado App, o compoñente App redirixirá o usuario a unha das dúas páxinas: Inicio ou Iniciar sesión, o estado actual do usuario (iniciado sesión, desconectado) ditará cal páxina á que se redirixe o usuario, un cambio no estado actual do usuario (por exemplo, cambiar de iniciado a sesión a pechada) debería desencadear unha redirección instantánea á páxina correspondente.

State

Como se mostra na ilustración anterior, queremos que o compoñente da aplicación considere o estado actual e que só represente unha das dúas páxinas - Inicio ou Inicio de sesión - en función dese estado actual.

Se o usuario é nulo, significa que non temos ningún usuario autenticado, polo que navegamos ata a páxina de inicio de sesión automaticamente e protexemos a páxina de inicio mediante a representación condicional. Se o usuario existe, facemos o contrario.

Agora que temos unha comprensión sólida do que se debe implementar, imos explorar algunhas opcións, pero primeiro imos configurar o noso proxecto React,

O repositorio do proxecto contén unha aplicación de backend de mostra que usaremos para implementar o lado do frontend (non imos entrar nela xa que non é o foco principal aquí, pero o código mantívose intencionalmente sinxelo para que non teña dificultades con el). )

Comezamos creando as seguintes páxinas e compoñentes:

  • Páxina de inicio

  • Páxina de inicio de sesión

  • Editar páxina de usuario

  • Compoñente da barra de navegación

  • Compoñente UserDropdown

Unha aplicación React con varias páxinas necesita unha navegación adecuada, para iso podemos usar react-router-dom para crear un contexto global de enrutador de navegador e rexistrar diferentes rutas de React.


yarn add react-router-dom

Sabemos que moitos lectores prefiren seguir titoriais, así que aquí tes o modelo de inicio para poñerte ao día. Esta rama de inicio usa DaisyUI para os compoñentes JSX de TailwindCSS predefinidos. Inclúe todos os compoñentes, páxinas e o router xa configurado. Se estás a pensar en seguir este titorial, crear todo o fluxo de autenticación por ti mesmo seguindo pasos sinxelos, comeza por fornear o repositorio primeiro. Despois de fornecer o repositorio, clonalo e comeza dende a rama start-herebranch:


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

Unha vez que tires da rama de inicio aquí:

  • Abre o proxecto co teu editor de código preferido

  • Cambia o directorio a frontend/

  • Instalar dependencias: fío

  • Iniciar un servidor de desenvolvemento: yarn dev·

A vista previa debería ser algo así:

Changing user name

O nome representado na barra de navegación (parte superior dereita) é unha variable de estado definida no compoñente principal da aplicación. A mesma variable pásase á barra de navegación e á páxina de inicio. O formulario sinxelo usado anteriormente actualiza realmente a variable de estado "nome" do compoñente EditPage.

Os dous enfoques que se presentan a continuación entrarán nos detalles da implementación:

Primeira aproximación: useState

useState()

useState é un dos ganchos React máis usados, permítelle crear e mutar estado nun compoñente React Functional. O compoñente useState ten unha implementación moi sinxela e é fácil de usar: para crear un novo estado, cómpre chamar a useState co valor inicial do seu estado e o gancho useState devolverá unha matriz que contén dúas variables: a primeira é o estado. variable que podes usar para facer referencia ao teu estado, e a segunda unha función que usas para cambiar o valor do estado: bastante sinxela.

Que tal vemos iso en acción? O nome representado na barra de navegación (parte superior dereita) é unha variable de estado definida no compoñente principal da aplicación. A mesma variable pásase á barra de navegación e á páxina de inicio. O formulario sinxelo usado anteriormente actualiza realmente a variable de estado "nome" do compoñente EditPage. A conclusión é a seguinte: useState é un gancho central que acepta un estado inicial como parámetro e devolve dúas variables con dous valores, a variable de estado que contén o estado inicial e unha función de configuración para a mesma variable de estado.

Desglosámolo e vexamos como se implementou iso en primeiro lugar.

  1. Creando a variable de estado "nome":

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

Atrezzo

Os atrezzo son un dos bloques básicos dun compoñente de reacción, conceptualmente, se pensas nun compoñente funcional de React como unha función Javascript, entón os atrezzo non son máis que os parámetros da función, xa que a combinación de atrezzo e o gancho useState pode ofrecerche un marco sólido. para xestionar o estado a través dunha sinxela aplicación React.

Os accesorios de React pásanse como atributos a compoñentes personalizados. Os atributos pasados ​​como atrezzo pódense desestruturar do obxecto props ao aceptalo como argumento, de xeito similar a isto:

Pasando atrezzo

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

Os atrezzos pódense aceptar e usar dentro dun compoñente funcional semellante aos argumentos de funcións normais. É porque "nome" se pasa como un accesorio ao compoñente Inicio, polo que podemos representalo no mesmo compoñente. No seguinte exemplo, estamos aceptando o props pasado usando a sintaxe de destruturación para extraer a propiedade name do obxecto props.

Aceptando atrezzo

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

Consello profesional

Abre a consola do navegador e observa como todos os compoñentes que usan o accesorio "nome" se vuelven a renderizar cando o estado cambia. Ao manipular unha variable de estado, React almacenará o seguinte estado, mostrará de novo o seu compoñente cos novos valores e actualizará a IU.

Components Re-rendering

use State Inconvenientes

Atrezzo-Perforación

A perforación de accesorios é un termo para referirse a unha xerarquía de compoñentes onde un conxunto de compoñentes necesita certos accesorios proporcionados por un compoñente pai, unha solución común que normalmente usan desenvolvedores inexpertos é pasar estes accesorios por toda a cadea de compoñentes, o problema con este O enfoque é que un cambio nalgún destes atrezzo provocará que toda a cadea de compoñentes se vuelva a renderizar, ralentizando de forma efectiva toda a aplicación como resultado destes renders innecesarios, os compoñentes no medio da cadea que non requiren estes accesorios. actúan como medios para transferir atrezzo.

Exemplo:

  • Definiuse unha variable de estado no compoñente principal da aplicación usando o gancho useState().

  • Pasouse un accesorio de nome ao compoñente Navbar

  • O mesmo accesorio aceptado na barra de navegación e pasou como accesorio unha vez máis ao compoñente UserDropdown

  • UserDropdown é o último elemento fillo que acepta o accesorio.

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

Imaxina o difícil que é manter unha aplicación React con diferentes capas de compoñentes que pasan e presentan o mesmo estado.

Crecente complexidade e calidade do código

Co uso de useState e props como o único medio de xestión do estado nunha aplicación de reacción, a base de código pode crecer rapidamente en complexidade, tendo que xestionar decenas ou centos de variables de estado, que poden ser duplicadas entre si, espalladas en diferentes ficheiros e Os compoñentes poden ser bastante desalentadores, calquera cambio nunha determinada variable de estado requirirá unha coidadosa consideración das dependencias entre os compoñentes para evitar calquera posible renderización adicional nunha aplicación xa lenta.

Segundo enfoque: API de contexto

A API de contexto é o intento de React de resolver os inconvenientes de usar só props e useState para a xestión do estado, en particular, a API de contexto xorde como unha resposta ao problema mencionado anteriormente sobre a necesidade de pasar accesorios a toda a árbore de compoñentes. Co uso do contexto, pode definir un estado para os datos que considere globais e acceder ao seu estado desde calquera punto da árbore de compoñentes: non hai máis perforación.

É importante sinalar que a API de contexto foi concibida inicialmente para resolver o problema do intercambio global de datos, datos como temas de IU, información de autenticación que é o noso caso de uso, idiomas, etc.), para outros tipos de datos que se deben compartir. entre máis dun compoñente pero non é necesariamente global para toda a aplicación, o contexto pode non ser a mellor opción, dependendo do caso de uso, pode considerar outras técnicas como composición de compoñentes que está fóra do ámbito deste artigo.

Cambiando ao contexto

Creando o contexto de autenticación

createContext é sinxelo, crea unha nova variable de contexto, toma un único parámetro opcional: o valor predeterminado da variable de contexto.

Vexamos isto en acción, primeiro cree un novo cartafol "contexts" e un novo ficheiro dentro del "Auth.jsx". Para crear un novo contexto, necesitamos invocar a función createContext(), asignar o valor devolto a unha nova variable Auth que se exportará a continuación:

./src/contexts/Auth.jsx

import { createContext } from "react";

export const Auth = createContext();

Proporcione o contexto de autenticación

Agora necesitamos expor a variable de contexto "Auth" que creamos anteriormente, para conseguilo usamos o provedor de contexto, o provedor de contexto é un compoñente que ten un accesorio "valor", podemos usar este accesorio para compartir un valor - nome – a través da árbore de compoñentes, ao envolver a árbore de compoñentes co compoñente provedor, facemos que ese valor sexa accesible desde calquera lugar dentro da árbore de compoñentes, sen necesidade de transmitir ese accesorio a cada compoñente fillo individualmente.

No noso exemplo de autenticación, necesitamos unha variable para manter o obxecto de usuario e algún tipo de setter para manipular esa variable de estado, este é un caso de uso perfecto para useState. Ao usar Context, debes asegurarte de que estás definindo os datos que queres proporcionar e de pasar eses datos (o usuario no noso exemplo) a toda a árbore de compoñentes aniñados dentro, polo que define un novo usuario variable de estado dentro do compoñente do provedor e finalmente pasamos tanto user como setUser dentro dunha matriz como o valor que o provedor expoñerá á árbore de compoñentes:

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

Outra cousa que podemos facer é mover a nosa variable de estado "nome" do compoñente principal da aplicación ao contexto Auth e expoñela a compoñentes anidados:

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

Agora só queda aniñar a nosa aplicación no mesmo compoñente AuthProvider que acabamos de exportar.

./src/main.jsx:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { AuthProvider } from "./contexts/Auth";

import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
  <AuthProvider>
    <App />
  </AuthProvider>
);

Debido a que estamos a renderizar o elemento secundario dentro de Auth.Provider, todos os elementos que están aniñados dentro do compoñente AuthProvider agora poden consumir o elemento de valor que pasamos a Auth.Provider. Pode parecer confuso, pero unha vez que experimentes con el, proba a proporcionar e consumir un estado global - Contexto. Despois de todo, só tiña sentido para min despois de experimentar coa API de contexto.

Consumir o contexto de autenticación

O paso final é sinxelo, usamos o gancho de contexto "useContext" para acceder ao valor que proporciona o fornecedor de contexto de "Auth", que no noso caso é a matriz que contén user e setUser, no seguinte código, podemos use useContext para consumir o contexto Auth dentro da barra de navegación. Isto só é posible porque a barra de navegación está aniñada dentro do compoñente da aplicación e, dado que AuthProvider envolve o compoñente da aplicación, o valor prop pode consumirse só usando o gancho useContext. Outra ferramenta fantástica que ofrece React para xestionar todos os datos aos que se pode acceder globalmente e tamén manipulados por calquera compoñente do consumidor.

./src/components/Navbar.jsx

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

 return (...)};

Teña en conta que xa non aceptamos ningún complemento no compoñente funcional Navbar(). Usamos useContext(Auth) para consumir o contexto Auth no seu lugar, collendo nome e setName. Isto tamén significa que xa non necesitamos pasar o accesorio a Navbar:

./src/App.jsx

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

Actualizando o contexto de autenticación

Tamén podemos usar a función setName proporcionada para manipular a variable de estado "nome":

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

Presentando o gancho useReducer().

No exemplo anterior usamos a API de contexto para xestionar e compartir o noso estado na árbore de compoñentes, quizais teñas notado que aínda estamos usando useState como a base da nosa lóxica, e isto está moi ben xa que o noso estado aínda é un obxecto simple. Neste momento, pero se tivesemos que ampliar as capacidades do noso fluxo de autenticación, definitivamente necesitaremos almacenar algo máis que só o correo electrónico do usuario que está actualmente conectado, e aquí é onde volvemos ás limitacións nas que nos atopamos anteriormente en canto a o uso de useState con estado complexo, afortunadamente, React resolve este problema proporcionando unha alternativa a useState para xestionar o estado complexo: introduza useReducer.

useReducer pódese pensar como unha versión xeneralizada de useState, necesita dous parámetros: unha función reductora e un estado inicial.

Nada interesante que destacar para o estado inicial, a maxia ocorre dentro da función redutor: comproba o tipo de acción que ocorreu e, dependendo desa acción, o reductor determinará que actualizacións aplicar ao estado e devolverá o seu novo valor. .

Mirando o código a continuación, a función redutora ten dous tipos de accións posibles:

  • "LOGIN": nese caso o estado do usuario actualizarase coas novas credenciais de usuario proporcionadas dentro da carga útil de accións.

  • "LOGOUT": nese caso, o estado do usuario eliminarase do almacenamento local e volverá ser nulo.

É importante ter en conta que o obxecto de acción contén un campo de tipo que determina que lóxica aplicar e un campo de carga útil opcional para proporcionar os datos necesarios para aplicar esa lóxica.

Finalmente, o gancho useReducer devolve o estado actual e unha función de envío que usamos para pasar unha acción ao reductor.

Para o resto da lóxica, é idéntico ao exemplo anterior:

./src/contexts/Auth.jsx

import { createContext, useEffect, useReducer, useState } from "react";

export const Auth = createContext();
import { createContext, useReducer } from "react";

export const Auth = createContext();
const reducer = (state, action) => {
  switch (action.type) {
    case "LOGIN":
      return { user: action.payload };

    case "LOGOUT":
      localStorage.removeItem("user");
      return { user: null };

    default:
      break;
  }
};

export const AuthProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, {
    user: null,
  });

  return (
    <Auth.Provider value={{ ...state, dispatch }}>{children}</Auth.Provider>
  );
};

Envío de accións en lugar de usar a función setState setter – por exemplo: setName –

Como acabamos de mencionar, usamos a función de envío para pasar unha acción ao reductor, no seguinte código, iniciamos unha acción LOGIN e proporcionamos o correo electrónico do usuario como carga útil, agora o estado do usuario actualizarase e este cambio activarase unha re-renderización de todos os compoñentes subscritos ao estado de usuario. É importante sinalar que un re-render só se activará se se produce un cambio real no estado, non se volverá a renderizar se o reductor devolve o mesmo estado anterior.

export default function Login() {
 const { dispatch } = useContext(Auth);


 const handleLogin = async (e) => {
   // Updating the global Auth context
   dispatch({ type: "LOGIN", payload: {email: email.current.value} });
 };

 return (...)};

Acceso de usuario

JWT Local storage

Consello profesional

Observe como o obxecto de usuario que recibimos despois dun inicio de sesión exitoso agora se almacena no localStorage.

Gancho personalizado para iniciar sesión

Agora que temos un bo control de useReducer, podemos encapsular aínda máis a nosa lóxica de inicio de sesión e pechada nos seus propios ganchos personalizados separados, mediante unha única chamada ao gancho de inicio de sesión, podemos xestionar unha chamada da API á ruta de inicio de sesión, recuperar o novo usuario. credenciais e gárdaas no almacenamento local, envíe unha chamada LOGIN para actualizar o estado do usuario, todo mentres se xestiona o tratamento de erros:

./src/hooks/useLogin.jsx

import { useContext, useState } from "react";
import { Auth } from "../contexts/Auth";

export const useLogin = () => {
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  const { dispatch } = useContext(Auth);

  const login = async (email, password) => {
    setIsLoading(true);
    setError(null);

    try {
      const response = await fetch("/api/users/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email, password }),
      });

      const json = await response.json();

      if (json.name === "Error") {
        setError(json.message);
        setIsLoading(false);
      }

      if (!response.ok) {
        setIsLoading(false);
        setError(json);
      }

      if (response.ok) {
        // Save the user and token in the localstorage
        localStorage.setItem("user", JSON.stringify(json));

        // Updating the global Auth context
        dispatch({ type: "LOGIN", payload: json });

        setIsLoading(false);
      }
    } catch (error) {
      console.log(error);
    }
  };

  return { error, isLoading, login };
};

Nota: para os usuarios de React máis avanzados entre os lectores, pode estarse preguntando por que non usamos a función de inicialización perezosa de useReducer para recuperar as credenciais do usuario, useReducer acepta un terceiro parámetro opcional chamado función init, esta función úsase no caso de que necesitamos aplicar algunha lóxica antes de poder obter o valor inicial do estado, a razón pola que non optamos por isto é unha simple cuestión de separación de preocupacións, o código deste xeito é máis sinxelo de entender e, como resultado, máis sinxelo de manter .

Páxina de inicio de sesión

Así é como se ve a parte superior da nosa páxina de inicio de sesión despois de usar o gancho useLogin() para extraer a función de inicio de sesión e de invocar a función de inicio de sesión coas credenciais enviadas por un usuario:

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

Tamén desactivamos a función Enviar cando o usuario envía o formulario:

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

E representando os erros de autenticación que recibamos do noso backend:

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

Rendering Errors

Mantendo o estado de usuario

Quizais se estea preguntando por que necesitamos almacenar o obxecto de usuario no localStorage, simplemente, queremos manter o usuario iniciado mentres o token non caduque. Usar localStorage é unha boa forma de almacenar bits de JSON, como no noso exemplo. Observe como se elimina o estado se actualiza a páxina despois de iniciar sesión. Isto pódese resolver facilmente usando un gancho useEffect para comprobar se temos un obxecto de usuario almacenado en localStorage, se o hai, iniciamos sesión o usuario automaticamente:

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

Ganchos personalizados para Logout

O mesmo ocorre co gancho Logout, aquí estamos enviando unha acción LOGOUT para eliminar as credenciais de usuario actuais tanto do almacenamento estatal como local:

./src/hooks/useLogout.jsx

import { useContext } from "react";
import { Auth } from "../contexts/Auth";

export const useLogout = () => {
  const { dispatch } = useContext(Auth);

  const logout = () => {
    // delete user from the localstorage
    localStorage.removeItem("user");
    // Wipe out the Auth context (user:null) / dipatch 'LOGOUT'
    dispatch({ type: "LOGOUT" });
  };

  return { logout };
};

Pecha de sesión do usuario

Para pechar a sesión dun usuario, engademos un evento de clic ao botón Pechar sesión que se atopa en UserDropdown.jsx e xestionémolo en consecuencia:

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

Protexer as rutas de reacción

O paso final na implementación da nosa aplicación é aproveitar o estado global do usuario para controlar a navegación do usuario, un recordatorio rápido sobre que comportamento debemos lograr: inicialmente o usuario é recibido pola páxina de inicio de sesión, a partir dese momento o usuario só pode acceder á páxina de inicio. despois dun inicio de sesión exitoso, o usuario será redirixido á páxina de inicio de sesión ao pechar a sesión.

Conseguimos isto coa axuda da biblioteca react-router-dom definindo 2 rutas: "/" e "/login", controlamos que compoñente renderizar en cada ruta usando o estado de autenticación global, auth avaliado como nulo representa un usuario non autenticado e viceversa:

./src/App.jsx

import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
import "./App.css";
import Navbar from "./components/Navbar";
import Home from "./pages/Home";
import Login from "./pages/Login";
import { useContext } from "react";
import { Auth } from "./contexts/Auth";

function App() {
  const { user } = useContext(Auth);
  return (
    <BrowserRouter>
      <div className="h-screen">
        <Navbar />
        <main className="px-4">
          <Routes>
            <Route
              path="/"
              element={user ? <Home /> : <Navigate to="/login" />}
            />
            <Route
              path="/login"
              element={!user ? <Login /> : <Navigate to="/" />}
            />
          </Routes>
        </main>
      </div>
    </BrowserRouter>
  );
}

export default App;

Diagrama de resumo

Diagram

Conclusión

Neste artigo tratamos de abordar o caso de uso sinxelo pero moi común de implementar a xestión estatal para un fluxo de traballo de autenticación, pasando polos diferentes enfoques, a razón de ser de cada un e os seus compromisos. A xestión do estado en frameworks do lado do cliente e en React en particular é un dos temas que máis se fala na comunidade frontend, simplemente porque pode facer ou romper o rendemento e a escalabilidade da súa aplicación. A gran cantidade de diferentes técnicas, patróns, bibliotecas e ferramentas que tentan resolver este problema da xestión estatal é abafadora, o noso obxectivo era darche unha comprensión sólida das prácticas para que poidas implementala na túa propia aplicación, para obter máis avanzada. técnicas e patróns de xestión do estado en aplicacións máis complexas, consulta o noso seguinte artigo onde entramos en redux para a xestión de estado escalable en React.

Próximamente

ContextAPI vs Redux Toolkit

Redux tivo moitos anos de adopción na comunidade antes do kit de ferramentas Redux, de feito, RTK presentouse como un modelo de inicio para iniciar a xestión do estado de redux en novas aplicacións (o seu nome inicial era "redux-starter-kit" en outubro de 2019), aínda que hoxe en día, hai un consenso xeral entre os mantedores de Redux e a comunidade de que o kit de ferramentas de Redux é a forma válida de traballar con redux. RTX abstrae moito da lóxica de Redux o que fai que sexa máis doado de usar, con moito menos detalle, e anima aos desenvolvedores a siga as mellores prácticas, unha diferenza principal entre as dúas é que Redux foi construído para non ter opinión, proporcionando unha API mínima e esperando que os desenvolvedores fagan a maior parte do traballo pesado escribindo as súas propias bibliotecas para tarefas comúns e xestionando a estrutura do código. isto deu lugar a un tempo de desenvolvemento lento e un código desordenado, o kit de ferramentas Redux engadiuse como unha capa adicional de abstracción que evita que os desenvolvedores caian nas súas trampas comúns, consulte a documentación oficial para obter máis información e os razoamentos dos seus mantedores aquí.


Career Services background pattern

Servizos de Carreira

Contact Section background image

Mantémonos en contacto

Code Labs Academy © 2024 Todos os dereitos reservados.