No tienes acceso a esta clase

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

No se trata de lo que quieres comprar, sino de quién quieres ser. Aprovecha el precio especial.

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

14 Días
23 Hrs
33 Min
45 Seg

useAuth: login y logout

11/30
Recursos

Aportes 19

Preguntas 3

Ordenar por:

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

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.

Mi Profe Facherito

Decidí organizar los archivos de esta manera.

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

Por si alguien también está haciendo el proyecto con TypeScript, comparto cómo me quedó auth.tsx:

import React, { useContext, useState } from 'react'
import type { PropsWithChildren } from 'react'
import { useNavigate } from 'react-router-dom'

interface Auth {
  user: { username: string } | null
  login: (username: string) => void
  logout: () => void
}

const AuthContext = React.createContext({})

function AuthProvider({ children }: PropsWithChildren) {
  const navigate = useNavigate()
  const [user, setUser] = useState<Auth['user']>(null)

  function login(username: string) {
    if (username) 
      setUser({ username })
      navigate('/profile')
  }
  
  function logout() {
    setUser(null)
    navigate('/')
  }

  const auth: Auth = { user, login, logout }

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

function useAuth() {
  const authContext = useContext(AuthContext) as Auth
  return authContext
}

export { AuthProvider, useAuth }

Podrían verificar que que exista un usuario con:

 <h1>{auth.user?.username}</h1>

el operador ‘?.’ verifica que dentro de objeto auth.user exista username, si no existe devolverá undefined y el h1 en la pagina estará vació.
.
o podrían hacer una condicional para mostrar un username por default:

const username = auth.user?.username ?? 'User936'

return (
  <h1>{username}</h1>
)

El operador de coalescencia nula ?? solo devuelve el valor del lado derecho (‘User936’) si el valor del lado izquierdo es null o undefined.
Y si no existe un ‘username’ en ‘auth.user?.username’ devolverá undefined

Esta genial el curso Juan pero más de 20 min de fake auth no me sirve. 😦

Esta clase estuvo bien intensa, tuve que mirarla 3 veces para poder entender bien.

Código de TypeScript de la clase:
AuthStore.tsx

import { createContext, FC, useState, PropsWithChildren } from 'react'
import { useNavigate } from 'react-router-dom'

interface User {
    username: string
}

interface Auth {
    user: User | null
    login: (user: User) => void
    logout: () => void
}

// interface Auth {
//     user: { username: string } | null
//     login: (user: Auth['user']) => void
//     logout: () => void
// }

const AuthContext = createContext({} as Auth);

const AuthProvider:FC<PropsWithChildren> = ({ children }) => {

    const navigate = useNavigate();
    const [user, setUser] = useState<Auth['user']>(null);

    const login:Auth['login'] = (user) => {
        setUser(user);
        navigate('/profile')
    }

    const logout:Auth['logout'] = () => {
        setUser(null);
        navigate('/');
    }

    const auth:Auth = { user, login, logout }

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

export { AuthProvider, AuthContext }

useAuth.ts

import { useContext } from "react"
import { AuthContext } from "./AuthStore"

const useAuth = () => {
    const auth = useContext(AuthContext);
    return auth;
}

export { useAuth }

ProfilePage

import { useAuth } from "./useAuth"

const ProfilePage = () => {

    const { user } = useAuth();

    return(
        <>
            <h1>Perfil</h1>
            <p>Welcome, { user?.username} </p>
        </>
    )
}

export { ProfilePage }

Basicamente lo que hace el metodo “login” es setear el estado de user name con el nombre de usuario que le pasamos, que viene del input
El metodo “logout” lo que hace es setear ese estado como null
Y todo esta guardado en el contexto al cual tenemos acceso con el hook de useAuth
Así lo compartimos con todos los componentes

AuthConsumer pensé en OutConsumer uwu, si alguien jugaba NBA en PlayStation allá por el año 2012 de repente conoce a ese Youtuber jajaja

useAuth: login y logout

.
Empezamos a desarrollar un flujo de navegación completo para aplicaciones que tengan autenticación y autorización. Esto significa que no todos los usuarios podrán tener acceso a rutas que deberían de ser privadas u ocultas si no se han autenticado. Incluso si ya hicieron login hay cosas que no queremos que vean, contenido que no cualquier usuario debe poder ver por cuestiones de autorización.
.
Lo primero que haremos en App es crear 2 nuevas rutas /login y logout con sus respectivos componentes a renderizar.
.

<Route path="/login" element={<LoginPage />} />
<Route path="/logout" element={<LogoutPage />} />

.
En Menu también añadimos estas 2 nuevas rutas al array de rutas.
.

const routes = [];
routes.push({
  to: '/',
  text: 'Home',
});
routes.push({
  to: '/blog',
  text: 'Blog',
});
routes.push({
  to: '/profile',
  text: 'Profile',
});
routes.push({
  to: '/login',
  text: 'Login',
});
routes.push({
  to: '/logout',
  text: 'Logout',
});

.
Vamos a necesitar un archivo auth.js el cual nos va permitir simular nuestro flujo de autenticación. Su objetivo principal es exportar un objeto que contenga nuestro AuthProvider y nuestro react hook useAuth.
.
En este archivo creamos un contexto para la autenticación. Dentro del provider de este contexto por medio de la propiedad value le pasamos un objeto auth que va a contener el estado de nuestro usuario user que por defecto es null cuando no está logeado; también contiene a las funciones de login y logout que lo que hacen es setear el estado del usuario y navigar como corresponda mediante useNavigate.
.

import React, { useContext } from 'react';
import { useNavigate } from 'react-router-dom';

const AuthContext = React.createContext();

function AuthProvider({ children }) {
  const navigate = useNavigate();
  const [user, setUser] = React.useState(null);

  const login = ({ username }) => {
    setUser({ username });
    navigate('/profile');
  };
  
  const logout = () => {
    setUser(null);
    navigate('/');
  };
  
  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,
};

.
El react hook useAuth lo que hace es simplemente llamar al contexto, guardarlo y exportarlo en una variable.
.
Finalmente, el AuthProvider es un componente que nos permitirá encapsular el contenido de nuestro HashRouter en App. Por lo que tendrá acceso a la información que puede proporcionar HashRouter, pero a la vez los componentes contenidos por AuthProvider como Menu o las rutas, tendrán acceso a las propiedades del objeto auth que proporciona el provider.
.

function App() {
  return (
    <>
      <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>
    </>
  );
}

.
Posteriormente, creamos o modificamos los componentes necesarios para este flujo, empezando por LoginPage, LogoutPage y Profile.
.
En LoginPage lo que podemos observar es que tenemos un pequeño formulario que nos permite ingresar el username, y mediante el react hook useAuth al realizar el evento de submit utilizaremos la función login que a su vez llama a auth.login para setear el valor del nombre de usuario y redirigirnos a la página de Profile de este.
.

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

function LoginPage() {
  const auth = useAuth();
  const [username, setUsername] = React.useState('');
  
  const login = (e) => {
    e.preventDefault();
    auth.login({ username });
  };
  
  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 };

.
En LogoutPage también se tiene un pequeño formulario que al realizar el evento de submit en este caso va a setear el estado del usuario en null y redirigirnos a la página principal / por medio del react hook useAuth y la función logout que a su vez utiliza a auth.logout.
.

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

function LogoutPage() {
  const auth = useAuth();
  
  const logout = (e) => {
    e.preventDefault();
    auth.logout();
  };
  
  return (
    <>
      <h1>Logout</h1>

      <form onSubmit={logout}>
        <label>¿Segura de que quieras salir?</label>

        <button type="submit">Salir</button>
      </form>
    </>
  );
}

export { LogoutPage };

.
Finalmente para completar esta parte del flujo tenemos a ProfilePage que va renderizar la página de perfil de usuario. Este utiliza al rect hook useAuth para recuperar la información del nombre de usuario y poder renderizarlo.
.
Sin embargo dará error si no se ha pasado a través de las etapas del flujo adecuadamente. Por lo que aún se debe implementar una forma de proteger las rutas para evitar este tipo de error, o condicionar el renderizado de forma que si el usuario es null entonces manejar el renderizado de otra manera.
.

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

function ProfilePage() {
  const auth = useAuth();
  
  return (
    <>
      <h1>Perfil</h1>
      <p>Welcome, {auth.user.username}</p>
    </>
  );
}

export { ProfilePage };

useAuth: login y logout


  • Definiendo rutas de Login y Logout.

    <Route path="/login" element={<LoginPage />} />
    <Route path="/logout" element={<LogoutPage />} />
    
  • Creando componentes LoginPage y LogoutPage.

    import React from "react";
    
    function LoginPage() {
      return <h1>Login</h1>;
    }
    
    export { LoginPage };
    
    import React from "react";
    
    function LogoutPage() {
      return <h1>Logout</h1>;
    }
    
    export { LogoutPage };
    
  • Agregar Links para login y logout al menú.

    import React from "react";
    import { NavLink } from "react-router-dom";
    
    function Menu() {
      return (
        <nav>
          <ul>
            {routes.map(route => (
              <li key={route.to}>
                <NavLink 
                  style={({ isActive }) => ({
                    color: isActive ? 'red' : 'blue'
                  })}
                  to={route.to}
                >
                  {route.text}
                </NavLink>
              </li>
            ))}
          </ul>
        </nav>
      )
    }
    
    const routes = [
      { to: '/', text: 'Home' },
      { to: '/blog', text: 'Blog' },
      { to: '/profile', text: 'Profile' }, 
      **{ to: '/login', text: 'Login' },
      { to: '/logout', text: 'Logout' }**
    ];
    
    export { Menu };
    
  • Creando un formulario para el login.

    import React from "react";
    
    function LoginPage() {
      **const [username, setUsername] = React.useState('');
    
      const login = (e) => {
        e.preventDefault();
        console.log(username);
      }**
    
      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 };
    
  • Creando un formulario para logout.

    import React from "react";
    
    function LogoutPage() {
    
      **const logout = (e) => {
        e.preventDefault();
        console.log('Logout');
      }**
    
      return (
        **<>
          <h1>Logout</h1>
    
          <form onSubmit={logout}>
            <label>¿Seguro de que quieres salir?</label>
    
            <button type="submit">Salir</button>
          </form>
        </>**
      );
    }
    
    export { LogoutPage };
    
  • Creamos un provider y un hook para la autentificación.

    **import React from "react";
    
    const AuthContext = React.createContext()
    
    function AuthPrvider({ children }) {
        const auth = {}
    
        return (
            <AuthContext.Provider value={auth}>
                { children }
            </AuthContext.Provider>
        )
    }
    
    function useAuth() {
        const auth = React.useContext(AuthContext)
        return auth;
    }
    
    export {
        AuthProvider,
        useAuth
    }**
    
  • Implementar el provider en la aplicación.

    import "./App.css";
    // more imports...
    **import { AuthProvider } from "./api/auth";**
    
    function App() {
      return (
        <>
          <HashRouter>
            **<AuthProvider>**
              <Menu />
    
              <Routes>
                <Route path="/" element={<HomePage />} />
    
                {/* More routes... */}
              </Routes>
            **</AuthProvider>**
          </HashRouter>
        </>
      );
    }
    
    export default App;
    
  • Creamos los métodos de login y logout en el provider y lo consumimos en LoginPage y LogoutPage respectivamente.

    ....
    
    const AuthContext = React.createContext()
    
    function AuthProvider({ children }) {
        **const navigate = useNavigate()
        const [user, setUser] = useState()
    
        const login = ({ username }) => {
            setUser({ username })
            navigate('/profile')
        }
    
        const logout = () => {
            setUser(null);
            navigate('/')
        }
    
        const auth = { user, login, logout };**
    
        return (
            <AuthContext.Provider value={auth}>
                { children }
            </AuthContext.Provider>
        )
    }
    
    ...
    
    import React from "react"
    import { useAuth } from "../api/auth"
    
    function LoginPage() {
      **const auth = useAuth()**
      const [username, setUsername] = React.useState('');
    
      const login = (e) => {
        e.preventDefault()
        **auth.login({ username })**
      }
    
      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 };
    
    import React from "react";
    import { useAuth } from "../api/auth";
    
    function LogoutPage() {
      **const auth = useAuth()**
    
      const logout = (e) => {
        e.preventDefault();
        **auth.logout()**
      }
    
      return (
        <>
          <h1>Logout</h1>
    
          <form onSubmit={logout}>
            <label>¿Seguro de que quieres salir?</label>
    
            <button type="submit">Salir</button>
          </form>
        </>
      );
    }
    
    export { LogoutPage };
    
  • Modificamos ProfilePage para mostrar el nombre del usuario logeado.

    import React from "react";
    import { useAuth } from "../api/auth";
    
    function ProfilePage() {
      **const auth = useAuth()**
    
      return (
        **<>
          <h1>Perfil</h1>
          <p>Welcome, {auth.user.username}</p>
        </>**
      );
    }
    
    export { ProfilePage };
    

<aside>
💡 En la siguiente clase manejaremos las rutas que seran privadas, es decir las que necesitarán autentificación para ingresar; y las rutas públicas, que serán las de autentificación.

</aside>

Por si les interesa trabajar con Typescript en este proyecto, aquí esta el código adaptado para ese lenguaje (muy similar a JS pero con tipado mas estricto): ```js //auth.tsx import React, { createContext, ReactNode, useContext, useState } from 'react'; import { useNavigate } from 'react-router-dom'; // aqui se define que tipo de dato es children type AuthProviderProps = { children: ReactNode; } // aqui se definen los tipos de datos que reciben las funciones y useState de Auth Provider type AuthContextType = { // el tipo de dato es un objeto con un tipo string o un valor nulo user: {username: string} | null; // login recibe una funcion funcion con "credenciales" que son un objeto con un dato tipo string login: (credentials: { username: string }) => void; // logout recibe un valor del tipo funcion logout: () => void; } // aqui dice que createContext puede recibr los tupos definidos en AuthContextType o puede ser indefinido, y por default lo haces indefinido const AuthContext = createContext<AuthContextType | undefined>(undefined); // React FC ayuda en typescript a definir un Function Component y permite pasar props prededifinas, en este caso es necesario para definir a "children" const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => { const navigate = useNavigate(); const [ user, setUser ] = useState<{username: string} | null>(null); const login = (credentials: { username: string }) => { setUser({ username: credentials.username }) navigate('/profile'); } const logout = () => { setUser(null) navigate('/'); } const auth = { user, login, logout } return( <AuthContext.Provider value={auth}> {children} </AuthContext.Provider> ) } const useAuth = () => { const auth = useContext(AuthContext); return auth; } export { AuthProvider, useAuth } // LoginPage.tsx import React, { useState } from 'react' import { useAuth } from './hooks/auth' // React FC ayuda en typescript a definir un Function Component y permite pasar props prededifinas, en este caso no es necesario usar React.FC const LoginPage: React.FC = () => { const auth = useAuth(); const [userName, setUserName] = useState<string>('') const login = ( e:any ) => { // en este caso defini que e o event puede tener cualquier tipo de valor o any e.preventDefault(); // aqui auth? puede tener un valor o puede ser null y te permite renderizar el componente reciba o no informacion ya que es un comportamiento esperado por TS auth?.login({ username: userName }) } return( <>

LoginPage

<form onSubmit={login}> <label> Nombre/ Usuario </label> <input type='text' value={userName} onChange={ e => setUserName(e.target.value)} /> <button type='submit'> Ir </button> </form> ) } export { LoginPage } // ProfilePage.tsx import React from 'react' import { useAuth } from './hooks/auth' const ProfilePage: React.FC = () => { const auth = useAuth(); return( <>

Welcome to ProfilePage {auth?.user?.username}

{/* aqui dices que auth? y user? puede ser undefined y por eso puedes renderizar el componente aunque no reciba valores de useAuth */} ) } export { ProfilePage } // LogoutPage.tsx import React from 'react' import { useAuth } from './hooks/auth' // React FC ayuda en typescript a definir un Function Component y permite pasar props prededifinas, en este caso no es necesario usar React.FC const LogoutPage: React.FC = () => { const auth = useAuth(); const logout = (e:any) => { // en este caso defini que e o event puede tener cualquier tipo de valor o any e.preventDefault(); // aqui auth? puede tener un valor o puede ser null y te permite renderizar el componente reciba o no informacion ya que es un comportamiento esperado por TS auth?.logout(); } return( <>

LogoutPAge

<form onSubmit={logout}> <label> Da click para salir </label> <button type='submit'> Salir </button> </form> ) } export { LogoutPage } // Аpp.tsx import { Menu } from './pages/components/Menux' import { HashRouter, Routes, Route } from 'react-router-dom' import { HomePage } from './pages/HomePage' import { BlogPage } from './pages/BlogPage' import { ProfilePage } from './pages/ProfilePage' import { BlogPost } from './pages/components/BlogPost' import { LoginPage } from './pages/LoginPage' import { LogoutPage } from './pages/LogoutPage' import { AuthProvider } from './pages/hooks/auth' // recuerda que HashRouter es un provider como funciona con React Context // queremos que el auth provider este dentro, porque es muy probable que necesite llamar metodos y hooks de hashprovider function App() { return ( <> <HashRouter> {/* debe de aparecer en todas las paginas, muy recomendable que este dentro de hash router */} <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

} /> </Routes> </AuthProvider> </HashRouter> ) } export default App ```
Después de 3 veces que vi la clase pude entender bien todo el proceso de Login y Logout, gracias teacher!!!

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.