No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripción 🔥

Aprende todo un fin de semana sin pagar una suscripción 🔥

Regístrate

Comienza en:

3D
23H
52M
28S

useAuth: login y logout

11/30
Recursos

Aportes 6

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

useAuth: login y logout

Ahora vamos a aprender como desplegar contenido en base a la Autenticación de usuarios, ósea que no todo el contenido de una aplicación va a ser público pata todos los usuarios, sino que tengamos algunas rutas privadas para personas que no se hayan autenticado, ósea hecho login y así mismo no mostrar contenido que es innecesario para personas que ya están registradas, como el mismo registro de usuario o contenido introductorio.

Vamos a hacer contenido que dependiendo el usuario se muestre o no se muestre, y también permitir tener privilegios o permisos dependiendo del rol que tengas.

Vamos entonces a crear nuevas rutas que nos permitan hacer todo esto:

import { LoginPage } from './Components/Routes/LoginPage/LoginPage';
import { LogoutPage } from './Components/Routes/LogoutPage/LogoutPage';

function App() {
  return (
    <>
      <HashRouter>
				<Routes>
	        ...
          
          <Route path='/login' element={<LoginPage />} /> 
          <Route path='/logout' element={<LogoutPage />} />
          <Route path='/profile' element={<ProfilePage />} />

        </Routes>
      </HashRouter>
    </>
  )
}

Y debemos crear nuestros respectivos componentes:

LoginPage.js

import React from 'react';

function LoginPage() {
  /* Para manejar el registro de usuario con el formilario haremos 
  uso del estado de React */
  const [username, setUsername] = React.useState('');

  /* Esta es la función que se ejecutará cuando ocurra el evento de 
  Submit */
  const login = (e) => {
    e.preventDefault();
  }

  // Aquí creamos un formulario para poder auteticarnos
  return (
    <>
      <h1>Login</h1>

      <form onSubmit={login}>
        <label>Escribe tu nombre de usuario</label>
        <input
          value={username}
          onChange={ e => setUsername(e.target.value)}
        />

        <button type="submit">Entrar</button>

      </form>
    </>
  );
}

export { LoginPage }

LogoutPage.js

import React from 'react';

function LogoutPage() {
  const logout = (e) => {
    e.preventDefault();
  }

  return (
    <>
      <h1>Logout</h1>

      <form onSubmit={logout}>
        <label>¿Segurx de que quieres salir?</label>

        <button type="submit">Salir</button>

      </form>
    </>
  );
}

export { LogoutPage }

En nuestro Menu.js vamos a crear dos nuevas rutas en nuestro Array routes:

...
const routes = [];

...
routes.push({
  to: '/login',
  text: 'Logout'
});
routes.push({
  to: '/logout',
  text: 'Login'
});

Si lo pensamos bien, no nos debería salir el componente Profile y Logout sin antes haber hecho un Login, vamos a trabajar entonces en esa lógica creando un archivo de autenticación:

auth.js

import React from 'react';

const AuthContext = React.createContext();

function AuthProvider({ children }) {
  const auth = {
    user,
    login,
    logout,
  }

  return (
    <AuthContext.Provider
      value={auth}
    >
      {children}
    </AuthContext.Provider>
  )
}

function useAuth() {
  const auth = React.useContext(AuthContext);
  return auth;
}

export {
  AuthProvider,
  useAuth,
}

Vamos a importar esta lógica al App.js:

...
import { AuthProvider, useAuth } from './Components/auth/auth'

function App() {
  return (
    <>
      {/* En este caso AuthProvider tiene que ir dentro de 
      HastRouter en caso de que AuthProvider necesite de algún 
      método o contenido que pueda proveer HashRouter */}
      <HashRouter>
        <AuthProvider>
          <Menu />

          <Routes>
            <Route path='/' element={<HomePage />} />
            <Route path='/blog' element={<BlogPage />}>
              <Route path=':slug' element={<BlogPost />} />
            </Route>
            
            <Route path='/login' element={<LoginPage />} />
            <Route path='/logout' element={<LogoutPage />} />
            <Route path='/profile' element={<ProfilePage />} />

            <Route path='/*' element={<p>Not Found</p>} />

          </Routes>
        </AuthProvider>

      </HashRouter>
    </>
  )
}

...

En este punto, en LoginPage.js ya podemos empezar a utilizar nuestro useAuth:

import { useAuth } from '../../auth/auth';
...

function LoginPage() {
  const auth = useAuth();
	...
}

Vamos de nuevo auth.js y seguimos con la lógica:

...
function AuthProvider({ children }) {
  /* Siguiendo la lógica, si user es null significa que no estamos 
  autenticados */
  const [user, setUser] = React.useState(null);

  // Ahora necesitamos darle un valor a nuestro usuario
  const login = ({ username }) => {
    setUser({ username });
  }

  // De la misma forma, debemos poder cerrar la sesión
  const logout = () => {
    setUser(null);
  }
	...
}

Ahora en LoginPage.js nuestro useAuth nos debe dar acceso al usuario y sus métodos:

function LoginPage() {
  const login = (e) => {
    e.preventDefault();
    auth.login({ username })
  }
}

Vamos de nuevo a auth.js y vamos a complementar la lógica:

function AuthProvider({ children }) {
  const navigate = useNavigate();

  const login = ({ username }) => {
    setUser({ username });
		/* Ahora cada vez que hagamos login nos redireccionará a la 
		página de profile */
    navigate('/profile');
  }

  const logout = () => {
		setUser(null);
    /* Aquí haremos redirect a la página principal */
    navigate('/');
  }

Pero para esto debemos añadir el contexto de autentificación a LogoutPage.js:

function LogoutPage() {
  const auth = useAuth();

  const logout = (e) => {
    e.preventDefault();
    auth.logout();
  }
}

Ahora en nuestra ProfilePage.js debemos completar esta lógica:

import { useAuth } from '../../auth/auth';

function ProfilePage() {
  const auth = useAuth();

  return (
    /* Ahora si nosotros nos registramos deberíamos poder ver 
		nuestro nombre de usuario en nuestra página de perfil */
    <>
      <h1>Perfil</h1>
      <h1>Welcome {auth.user.username}</h1>
    </>
  );
}

Y listo, ahora solo nos queda el que no podamos entrar a profile sino hasta que hayamos hecho login, lo cual haremos a continuación.

Por si alguien tien este error: usando Vite

[vite] Internal server error: Failed to parse source for import analysis because the content contains invalid JS syntax. If you are using JSX, make sure to name the file with the .jsx or .tsx extension.
  Plugin: vite:import-analysis
  File: /home/naiper/cursos/33-react-router/src/helpers/auth.js
  33 |      logout
  34 |    };
  35 |    return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
     |                                                                                ^
  36 |  }
  37 |
      at formatError (file:///home/naiper/cursos/33-react-router/node_modules/vite/dist/node/chunks/dep-db16f19c.js:40862:46)
      at TransformContext.error (file:///home/naiper/cursos/33-react-router/node_modules/vite/dist/node/chunks/dep-db16f19c.js:40858:19)
      at TransformContext.transform (file:///home/naiper/cursos/33-react-router/node_modules/vite/dist/node/chunks/dep-db16f19c.js:37530:22)
      at async Object.transform (file:///home/naiper/cursos/33-react-router/node_modules/vite/dist/node/chunks/dep-db16f19c.js:41111:30)
      at async loadAndTransform (file:///home/naiper/cursos/33-react-router/node_modules/vite/dist/node/chunks/dep-db16f19c.js:37373:29)

Lo que hice fue cambiar el archivo auth.js por un auth.jsx

Otra solución que encontré fue cambiar la configuración del vite.config.js

Agregué una regla: “Enable hmr overlay with vite react and ts”

Pero lamentablemente no me sirvió, sólamente me quitó el error en Vite pero me dejó en consola.

Gracias Juan. De hecho en primera instancia creí que era mejor que el AuthProvider fuera el componente de más arriba. Pero luego de tu explicación, comprendo qué lógica debo tener a la hora de definir cómo organizar estos Providers.

Cuando relacione el label con el input utilizando for, react me sugirió cambiarlo por htmlFor.

  <label htmlFor='input-login'>Escribe tu nombre de usuario:</label>
        <input
        value={username}
        onChange={e => setUsername(e.target.value)}
        id='input-login'/>

Discriminar no siempre es malo, sacar a Freddy de estos permisos es una buena manera de trabajo, ya que, cada quien tiene una chamba y autonomía.

En otras palabras, estos cursos discriminan información. Así es, información que no es relevante o que es falsa o de baja calidad.

Ya que actualmente rect-router está en la versión 6.8 he estado usando las nuevas características.
Así fue como acomodé las rutas:

const router = createHashRouter([
  { 
    element: <AuthProvider/>,
    children:[
      {  
        path: "/",
        element:<Layout/>,
        errorElement: <ErrorPage/>,
        children:[  
          {
            index:true,
            path: "/",
            element:<HomePage className="container"/>,
          },
          {
            path: "/login",
            element:<LonginPage/>,
          },
          {
            path: "/logout",
            element:<LogoutPage/>,
          },
          {
            path: "/profile",
            element:<ProfilePage/>,
          },
          {
            path: "/blog",
            element:<BlogPage/>,
            loader:postLoader,

          },
          {
            path: "/blog-post/:slug",
            element:<BlogPost/>,
            loader:loaderBlogPost,  
          },
        ]
      } 
    ]
  },
])

function App() {
  
  return (
    <React.Fragment>
      <RouterProvider router={router}/>
    </React.Fragment>

)
}

<AuthProvider/> Tiene como hijos al resto de las rutas para poder compartir el contexto. También tengo un componente Layout el cual uso como base agregar tanto el menú como las rutas hijas que se rendericen dentro de él dependiente de la url.

Así se ve el componente <AuthProvider/>:

import React from "react";
import { Outlet, useNavigate } from "react-router-dom";



const AuthContext = React.createContext();

function AuthProvider(){
    const [username, setUsername] = React.useState(null);
    const navigate = useNavigate();

    const login = ()=>{
        navigate("/profile");
    }
    const logout = ()=>{
        navigate("/");
    }
    
    const auth = {username, login, logout};
    return(
        <AuthContext.Provider value={auth}>
            <Outlet></Outlet>
        </AuthContext.Provider>
    )
}

function useAuth(){
    const data = React.useContext(AuthContext);
    return data
}

export {AuthProvider, useAuth}

Haciendo uso de un componete especial de react-router llamado Outlet; se puede traer a los hijos(childrens) especificados en las rutas.

Hasta el momento funcionó todo el ejercicio de esta clase.