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: 鈥淓nable 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.