Introducción al curso avanzado de React

1

Qué necesitas para este curso y qué aprenderás sobre React.js

2

Proyecto y tecnologías que usaremos

Preparando el entorno de desarrollo

3

Clonando el repositorio e instalando Webpack

4

Instalación de React y Babel

5

Zeit es ahora Vercel

6

Linter, extensiones y deploy con Now

Creando la interfaz con styled-components

7

¿Qué es CSS-in-JS?

8

Creando nuestro primer componente: Category

9

Creando ListOfCategories y estilos globales

10

Usar información real de las categorías

11

Creando PhotoCard y usando react-icon

12

SVGR: de SVG a componente de ReactJS

13

Creando animaciones con keyframes

Hooks

14

¿Qué son los Hooks?

15

useEffect: limpiando eventos

16

useCategoriesData

17

Usando Intersection Observer

18

Uso de polyfill de Intersection Observer e imports dinámicos

19

Usando el localStorage para guardar los likes

20

Custom Hooks: useNearScreen y useLocalStorage

GraphQL y React Apollo

21

¿Qué es GraphQL y React Apollo? Inicializando React Apollo Client y primer HoC

22

Parámetros para un query con GraphQL

23

Usar render Props para recuperar una foto

24

Refactorizando y usando variables de loading y error

25

Usando las mutaciones con los likes

Reach Router

26

¿Qué es Reach Router? Creando la ruta Home

27

Usando Link para evitar recargar la página

28

Creando la página Detail

29

Agregando un NavBar a nuestra app

30

Estilando las páginas activas

31

Rutas protegidas

Gestión del usuario

32

Introducción a React.Context

33

Creación del componente UserForm; y Hook useInputValue

34

Estilando el formulario

35

Mutaciones para registro

36

Controlar estado de carga y error al registrar un usuario

37

Mutaciones para iniciar sesión

38

Persistiendo datos en Session Storage

39

Hacer like como usuario registrado

40

Mostrar favoritos y solucionar fetch policy

41

Cerrar sesión

Mejores prácticas, SEO y recomendaciones

42

Últimos retoques a las rutas de nuestra aplicación

43

React Helmet

44

Midiendo el performance de nuestra app y usando React.memo()

45

React.lazy() y componente Suspense

46

Usando PropTypes para validar las props

47

PWA: generando el manifest

48

PWA: soporte offline

49

Testing con Cypress

Conclusiones

50

¡Felicidades!

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
21H
46M
9S
Curso de React Avanzado

Curso de React Avanzado

Miguel Ángel Durán

Miguel Ángel Durán

Rutas protegidas

31/50
Recursos

Con el método render props realizaremos rutas de autenticación para saber si el usuario ha iniciado sesión o no y podremos mostrar contenido dependiendo de las props que le estemos pasando.

Aportes 28

Preguntas 1

Ordenar por:

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

o inicia sesión.

Bueno a mi personalmente, me gusta tener las rutas separadas en un componente… Me parece que como desarrollador algo que siempre vas a ver son las rutas para entender el sistema al igual que ves el package.json
A si que les dejo como separe las rutas…

App.js

import React from 'react'
import { GlobalStyle } from './styles/GlobalStyles'
import { Logo } from './components/Logo/Index'
import { NavBar } from './components/NavBar/index'
import { Route } from './router/Router'

export const App = () => (
  <>
    <Logo />
    <GlobalStyle />
    <Route />
    <NavBar />
  </>
)

Router.js

import React from 'react'
import { Router } from '@reach/router'
import { Home } from '../pages/Home'
import { Detail } from '../pages/Detail'
import { PrivateRoute } from './PrivateRoute'

const isAuth = false

export const Route = () => (
  <>
    <Router>
      <Home path='/' />
      <Home path='/pet/:id' />
      <Detail path='/detail/:id' />
    </Router>
    <PrivateRoute isAuth={isAuth} />
  </>
)

PrivateRoute.js

import React from 'react'
import { Router } from '@reach/router'
import { Favs } from '../pages/Favs'
import { NotRegisteredUser } from '../pages/NotRegisteredUser'
import { User } from '../pages/User'

export const PrivateRoute = ({isAuth}) => {
  return (
    <Router>
      {
        isAuth ? (
          <>
            <Favs path='/favs' />
            <User path='/user' />
          </>
        ) : (
          <>
            <NotRegisteredUser path='/favs' />
            <NotRegisteredUser path='/user' />
          </>
        )
      }
    </Router>
  )
}

Inclusive creo que se puede sacar el router De privateRouter para a si solo declararlo en un lugar solo

Un poquito más cómodo de utilizar en la actualidad mediante react-router-dom, utilizando el prop render de Route:

import { Route, Switch, BrowserRouter as Router, Redirect } from 'react-router-dom'
import { Logo } from '../components/Logo'
import { ListOfCategories } from '../components/ListOfCategories'
import { Details } from '../pages/Details'
import { Home } from '../pages/Home'
import { Navbar } from '../components/Navbar'
import { Favorite } from '../pages/Favorites'
import { Register } from '../pages/Register'
import { User } from '../pages/User'

const isLogged = true

export const Routes = () => {
  return (
    <Router>
      <Logo />
      <ListOfCategories />
      <Switch>
        <Route exact path='/' component={Home} />
        <Route exact path='/category/:id' component={Home} />
        <Route exact path='/details/:id' component={Details} />
        <Route exact path='/favs' render={() => isLogged ? <Favorite /> : <Redirect to='/register' />} />
        <Route exact path='/user' render={() => isLogged ? <User /> : <Redirect to='/register' />} />
        <Route exact path='/register' component={Register} />
      </Switch>
      <Navbar />
    </Router>
  )
}

.
Vídeo actualizado del profesor @midudev al 2021: https://www.youtube.com/watch?v=9CYuUNPbP34
.
PD: Este curso está muy bueno, pero en serio, ya huele a encerrao. ¡Actualización YA!

Buenas, para los que estén usando React Router v6, implementé un condicional dentro del element de cada Route:

import React, { useState } from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { GlobalStyle } from "./styles/GlobalStyles";

import { Logo } from "./components/Logo";
import { Home } from "./pages/Home";
import { Detail } from "./pages/Detail";
import { NavBar } from "./components/NavBar";
import { User } from "./pages/User";
import { Favs } from "./pages/Favs";
import { NotRegisteredUser } from "./pages/NotRegisteredUser";

export const App = () => {
  const [isLogged, setIsLogged] = useState(true);

  return (
    <BrowserRouter>
      <GlobalStyle />
      <Logo />
      <Routes>
        <Route path='/' element={<Home />} />
        <Route path='/pet/:id' element={<Home />} />
        <Route path='/detail/:detailId' element={<Detail />} />
        <Route path='/favs' element={isLogged ? <Favs /> : <NotRegisteredUser />} />
        <Route path='/user' element={isLogged ? <User /> : <NotRegisteredUser />} />
      </Routes>
      <NavBar />
    </BrowserRouter>
  );
}

Espero les sirva, saludos!

una consulta, esta variable en el mundo real puede ser modificada con herramientas del desarrollador que proveen los navegadores?? lo pregunto por si esta solución podría ser puesta en producción así como esta.

Hola compañeros, así lo plantee usando react-router-dom

import React from 'react'
import { Logo } from './components/Logo'
import { Home } from './pages/Home'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { GlobalStyle } from './components/styles/GlobalStyles'
import { NavBar } from './components/NavBar'

import { Detail } from './pages/Detail'
import { Favorites } from './pages/Favs'
import { User } from './pages/User'
import { NotRegisteredUser } from './pages/NotRegistered'

const App = () => {
  const isLogged = false

  return (
    <BrowserRouter>
      <GlobalStyle />
      <Logo />
      <Routes>
        <Route exact path='/' element={<Home />} />
        <Route path='/pet/:id' element={<Home />} />
        <Route path='/detail/:id' element={<Detail />} />
        <Route path='/favs' element={isLogged ? <Favorites /> : <NotRegisteredUser />} />
        <Route path='/user' element={isLogged ? <User /> : <NotRegisteredUser />} />
      </Routes>
      <NavBar />
    </BrowserRouter>
  )
}

export { App }

Ya hay métodos más sencillos para renderizar rutas privadas con react router dom

export const App: FC = () => {
  const isLogged = false;
  return (
    <Router>
      <div>
        <GlobalStyled />
        <Logo />
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/pet/:id" component={Home} />
          <Route path="/detail/:detailId" component={Detail} />
          <Route path="/favs" render={ ()=> isLogged && <Favs /> || <NotRegisteredUser /> }/>
          <Route path="/user" render={ ()=> isLogged && <User /> || <NotRegisteredUser /> }/>
        </Switch>
        <NavBar />
      </div>
    </Router>
  );
};

Hola, les dejo mi implementación con Next.js:

Creé un contexto para manejar la autenticación, en la carpeta context/auth.js:

import { createContext, useContext } from 'react';

export const AuthContext = createContext();

export function useAuth() {
  return useContext(AuthContext);
}

En _app.js creé un estado para manejar la autenticación y puse el contexto cubriendo toda la app:

function MyApp({ Component, pageProps }) {
  const [authTokens,setAuthTokens] = useState(true)
  return (
    <AuthContext.Provider value={{ authTokens, setAuthTokens }}>
      <ApolloProvider client={client}>
        <GlobalStyle />
        <Logo />
        <Component {...pageProps} />
        <NavBar />
      </ApolloProvider>
    </AuthContext.Provider>
  );
}

También creé un nuevo componente que se llama PrivateRoute, en el cual hago uso del contexto para saber si la autenticación ya se dio:

import React from 'react';
import {useAuth} from 'context/auth'
const PrivateRoute = ({children}) => {
    const {authTokens} = useAuth()
    return <>{!authTokens ? <p>Not Logged</p> : <>{children}</>}</>;
}
 
export default PrivateRoute;

Finalmente, dentro de cada componente que tengo que proteger, uso el PrivateRoute, por ejemplo en favs:

import React from 'react';
import PrivateRoute from '@components/PrivateRoute'
const Favoritos = () => {
    
    return (
        <PrivateRoute>
            <p>Favs</p>
        </PrivateRoute>
    );
}
 
export default Favoritos;

En este punto, faltaría en _app.js hacer toda la lógica de autenticación.

Les dejo mi repositorio en Nextjs con la solución:

Mi maldición de los () continúa, ahora me gasté más de 15 min con un ) mal puesto en el Router…

Comienzo a creer que no tengo talento para esto…

Uds. ven la ventaja de los render props ? No los veo muy práctico, puedo hacer las “rutas protegidas” con esto sin tanta complejidad:

        {isAuth ? (
          <>
            <Favs path="/favs" />
            <User path="/user" />
          </>
        ) : (
          <>
            <NotRegisteredUser path="/favs" />
            <NotRegisteredUser path="/user" />
          </>
        )}
        	

Les comparto una guía resumida de React Context en freecodecamp que repasa la forma de uso y definición, los casos de uso mas comunes y para lo que no se recomienda su uso por los problemas que puede crear.
También lo contrasta con Redux.
Está en inglés y su redacción no es la mejor pero se entiende bien.

https://www.freecodecamp.org/news/react-context-for-beginners/

Espero les sume!!!

Es más fácil hoy en día con React Router V6

import { BrowserRouter, Route, Routes, Navigate } from 'react-router-dom';
import { GlobalStyle } from './styles/GlobalStyles';
import { Logo } from './components/Logo/index';
import { Home } from './pages/Home';
import { Detail } from './pages/Detail';
import { Navbar } from './components/Navbar/index';
import { Favs } from './pages/Favs';
import { User } from './pages/User';
import { NotRegisteredUser } from './pages/NotRegisteredUser';

const userLogged = false;

function App() {
	return (
		<>
			<BrowserRouter>
				<GlobalStyle />
				<Logo />
				<Routes>
					<Route
						path='/'
						element={userLogged ? <Home /> : <Navigate to='/login' />}
					/>
					<Route
						path='/favs'
						element={userLogged ? <Favs /> : <Navigate to='/login' />}
					/>
					<Route path='/user' element={<User />} />
					<Route path='/login' element={<NotRegisteredUser />} />
					<Route path='/pet/:id' element={<Home />} />
					<Route path='/detail/:detailId' element={<Detail />} />
				</Routes>
				<Navbar />
			</BrowserRouter>
		</>
	);
}

export default App;

<Route
            exact
            path="/favs"
            component={isAuth ? Favs : NotRegisteredUser}
          />
          <Route
            exact
            path="/user"
            component={isAuth ? User : NotRegisteredUser}
          />

En ves de usar dos veces el componente de NoRegisterUser use lo siguiente

 <Router>
      <Register default  path='/register'/>
 </Router>

una pregunta. Si hago mutations a la base de datos se cargan? Osea mis cambios los pueden usar otros que tengan acceso a la api?

tengo una duda con los archivos veo que la extensión es js y no jsx, existe alguna diferencia actualmente entre usar js o jsx?? puedo usar react con archivos .ts ??

Para quien esté usando React Router 6.4 y esté usando la nueva función createBrowserRouter(), así lo hice yo en App.js:

import React from 'react'
import { GlobalStyle } from './styles/GlobalStyle'
import { Logo } from './components/Logo'
import { Home } from './pages/Home'
import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom'
import { Detail } from './pages/Detail'
import { Favs } from './pages/Favs'
import { NotRegisteredUser } from './pages/NotRegisteredUser'
import { User } from './pages/User'
import { NavBar } from './components/NavBar'

const isUserLogged = true

const Container = () => (
  <>
    <Logo />
    <Outlet />
    <NavBar />
  </>)

const router = createBrowserRouter(([
  {
    path: '/',
    element: <Container />,
    children: [
      {
        path: '/',
        element: <Home />
      },
      {
        path: '/pet/:id',
        element: <Home />
      },
      {
        path: '/detail/:detailId',
        element: <Detail />
      },
      {
        path: '/favs',
        element: isUserLogged ? <Favs /> : <NotRegisteredUser />
      },
      {
        path: '/user',
        element: isUserLogged ? <User /> : <NotRegisteredUser />
      }
    ]
  }
]))

export const App = () => {
  return (
    <div>
      <GlobalStyle />
      <RouterProvider router={router} />
    </div>
  )
}

App.js

import React from "react";
import { BrowserRouter, Routes, Route} from "react-router-dom";
//styles
import { GlobalStyle } from "./Styles/GlobalStyles";
// import { Routes } from './Routes'
import { Home } from './Pages/Home';
import { Detail } from "./Pages/Detail";
import { Favs } from "./Pages/Favs";
import { User } from "./Pages/User";
import { NotRegisteredUser } from "./Pages/NotRegisteredUser";

import { Logo } from './Components/Logo';
import { NavBar } from './Components/NavBar';

const UserLogged = ({children}) =>{
    return children({isAuth: false})
}

export const App = () =>{
    const  urlParams = new window.URLSearchParams(window.location.search)
    const detailId = urlParams.get('detail')
    console.log(detailId)
    return (
        <BrowserRouter>
        <GlobalStyle />
        <Logo />
        <Routes>
            <Route path='/' element={<Home />} />
            <Route path='/pet/:id' element={<Home />} />
            <Route path='/detail/:id' element={<Detail />} />
        </Routes>
        <UserLogged>
            {
                ({isAuth}) =>
                    isAuth
                    ?
                    <Routes>
                        <Route path='/favs' element={<Favs />} />
                        <Route path='/user' element={<User/>} />
                    </Routes>
                    :
                    <Routes>
                        <Route path='/favs' element={<NotRegisteredUser />} />
                        <Route path='/user' element={<NotRegisteredUser />} />
                    </Routes>
            }
        </UserLogged>
        <NavBar />
        </BrowserRouter>
    )
} 

Con react-router-dom

const UserLogged = ({ children }) => {
    return children({ isAuth: false });
}

const App = () => {
    return (
    <BrowserRouter>
            <GlobalStyle />
            <Logo />
            <Switch>
                <Route exact path='/'render={(props) =><Home {...props} />} />
                <Route exact path='/pet/:id'render={(props) =><Home {...props} />} />
                <Route exact path='/detail/:detailId' component={Detail}/>
                <UserLogged>
                    {
                        ({ isAuth }) =>
                            isAuth
                            ? <>
                                <Route exact path='/favs' component={Favs} />
                                <Route exact path='/user' component={User} />
                              </>
                            : <>
			         // ESTA ES OTRA FORMA DE UTILIZAR 1 RUTA EN LUGAR DE 2
                                  <Route component={NotRegisteredUser} />
                              </>
                    }
                </UserLogged>
     </Switch>
     <NavBar />
    </BrowserRouter>
    );
};

es decir esto sería como un guard¿?

se puede hacer como en Angular que en la ruta le dices si usa un Auth y asi no creas un Route para cada sección¿? lo veo muy repetido eso NotRegistedUser con el path para favs y user¿?

{ 
    path: 'profile',
    component: ProfileComponent,
    canActivate: [AuthGuard] 
  },```

Me gusta más esta validación y reach/router lo hace tan simple

Hola, ¿como hago que al guardar el eslint me solucione las identaciones?

//Lo que hago es redireccionar si no esta autorizado
const Routes = () => (
<BrowserRouter>
<Switch>
<Route
path="/locales"
strict
sensitive
render={() => {
if(userid){
return <Locales />
}else{
return <Redirect from="/locales" to="/" />
}
}}
/>

Me encantan las Render Props!

import React from 'react';

import { Router } from '@reach/router';

import Layout from './components/Layout/Layout';
import Home from './pages/Home';
import Details from './pages/Details';
import Favorites from './pages/Favorites';
import User from './pages/User';
import UnregisteredUser from './pages/UnregisteredUser';

import useUserLogged from './hooks/useUserLogged';


const App = () => {
  const { isAuth } = useUserLogged(true);

  return (
    <>
      <Layout>
        <Router>
          <Home path="/" />
          <Home path="/pet/:CategoryId" />
          <Details path="/detail/:detailId" />
        </Router>
        {isAuth
          ? (
            <Router>

              <Favorites path="/favorites" />
              <User path="/user" />
            </Router>
          )
          : (
            <Router>

              <UnregisteredUser path="/favorites" />
              <UnregisteredUser path="/user" />
            </Router>
          )}

      </Layout>
    </>
  );
};

export default App;

Con el método render props realizaremos rutas de autenticación para saber si el usuario ha iniciado sesión o no y podremos mostrar contenido dependiendo de las props que le estemos pasando.

Tenia el problema que en el navbar el home siempre me aparecía activo, lo solucioné cambiando el / por el /home, creo que si por ejemplo estas en /user cuenta como activo la ruta / y la ruta /user

Estoy implementando rutas en un proyecto de la siguiente forma :

<Layout>
       <Router>
         <Home path="/" />
         {!isAuth && <Login path="/login"  /> }
         {!isAuth && <Redirect from='/user/questionnaires/new' to='/login' noThrow />}
         {!isAuth && <Redirect from='/user/questionnaires/detail/:detailId' to="/login" noThrow />}
         {!isAuth && <Redirect from='/user' to='/login' noThrow />}
         {isAuth &&  <Redirect from='/login' to='/user' noThrow />}      
         <UserHome path="/user"   />
         <NewQuestionary path="/user/questionnaires/new" />
         <QuestionnaireDetail path="/user/questionnaires/detail/:detailId" />
       </Router>
     </Layout>

Pero este redirect

  {!isAuth && <Redirect from='/user/questionnaires/detail/:detailId' to="/login" noThrow />}

me manda este error :

Uncaught Invariant Violation: <Redirect from="/user/questionnaires/detail/:detailId to="/login"/> has mismatched dynamic segments, ensure both paths have the exact same dynamic segments.

¿como debo configurar mi redirect para que funcione de forma correcta?

Código: