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!

Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Curso de React Avanzado

Curso de React Avanzado

Miguel Ángel Durán

Miguel Ángel Durán

Hacer like como usuario registrado

39/50
Recursos

Un JSON Web Token (JWT) es un estándar abierto para crear tokens y asegurar que el envío de datos es confiable y seguro. Van a ser muy útiles para implementar la lógica de los likes pues solamente los usuarios autentificados podrán dar like.

Un JWT se conforma de 3 partes:

  1. Header: Es un objeto que define qué algoritmo y tipo tiene el token.
  2. Payload: La información que almacenamos en el token.
  3. Verify Signature: Una encriptación del header más el payload más tu llave secreta.

Para utilizar nuestro JWT necesitamos añadirlo al header authorization de las peticiones HTTP que hagamos con el texto Bearer [token].

Aportes 30

Preguntas 7

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Mi solución basada en las últimas actualizaciones de la documentación
‎

https://jwt.io/ Acá puede decodificar los JWT y ver que información están enviando.

Este es el codigo que yo utilice ya que ando usando @apollo/client

import React from 'react'
import { ApolloClient, ApolloProvider as Aprovider, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'

const httpLink = createHttpLink({
  uri: 'https://petgram-server-anthony-3vrjckvsb.vercel.app/graphql'
})

const authLink = setContext((_, { headers }) => {
  const token = window.sessionStorage.getItem('token')
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : ''
    }
  }
})

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

export const ApolloProvider = ({ children }) => (
  <Aprovider client={client}>
    {children}
  </Aprovider>
)

Lo separe al igual que el Context para que no se vieran con tanta informacion el index, me guie de la documentacion de apollo https://www.apollographql.com/docs/react/networking/authentication/

La cual muestra un ejemplo, lo que pude entender es que usaremos las variables setContext y createHttpLink para luego concatenarlas en el ApolloClient y asi poder interceptar las peticiones que se hagan para interactuar segun si se tiene el token o no

Les comparto el codigo de @Félix Anderson, al cual solo he agregado el window.sessionStorage en lugar de sessionStorage y en un formato que puedan copiar, gracuas Félix!

import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App'
import { ApolloClient, InMemoryCache, ApolloProvider, ApolloLink, from, HttpLink } from '@apollo/client'
import Context from './Context'
import { onError } from '@apollo/client/link/error'

const authMiddleware = new ApolloLink((operation, forward) => {
  const token = window.sessionStorage.getItem('token')
  if (token) {
    operation.setContext({
      headers: {
        authorization: `Bearer ${token}`
      }
    })
  }
  return forward(operation)
})
const errorMiddleware = onError(({ networkError }) => {
  if (networkError && networkError.result.code === 'invalid_token') {
    window.sessionStorage.removeItem('token')
    window.location = '/user'
  }
})

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: from([
    errorMiddleware,
    authMiddleware,
    new HttpLink({
      uri: 'https://petgram-server-mcvictor.mcvictormurillo.vercel.app/graphql'
    })
  ])
})

ReactDOM.render(
  <Context.Provider value={{ isAuth: false }}>

    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </Context.Provider>

  , document.getElementById('app'))

SI por alguna razon iniciaron a usar apollo con base a este comentario

ALTO AQUI

En su codigo usaron:

import { ApolloClient } from'apollo-boost'

Y deben de hacerlo como:

import ApolloClient from 'apollo-boost'

De lo contrario tendrán que añadir mas código y hacer mucha configuración perdiendo el poder de ApolloBoost

El código final de la clase queda asi:

import ApolloClient from'apollo-boost'

const client = new ApolloClient({
  uri: 'https://petgram-server.miguelseguramx.now.sh/graphql',
  request: operation => {
    const token = window.sessionStorage.getItem('token')
    const authorization = token ? `Bearer ${token}` : ''
    operation.setContext({
      headers: {
        authorization
      }
    })
  },
  onError: error => {
    const { networkError } = error
    if (networkError && networkError.result.code === 'invalid_token') {
      window.sessionStorage.removeItem('token')
      window.location.href = '/'
    }
  }
})

Les dejo mi código porseacaso, lo hice con guiandome de otros aportes y con esta documentación https://www.apollographql.com/docs/react/networking/advanced-http-networking/#customizing-request-logic

src > index.js

src > components > PhotoCard > index.js

Con que curso puedo crear un API de backend como esta ❤️!

Mi porte para que puedan tener la autenticación junto con el manejo de errores🤗🤗 con @apollo/client :

A mi me pasa que el servidor (API en GraphQL), recuerda el usuario registrado solo por un momento, luego arroja que no existe

import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App.js'
import { ApolloClient, InMemoryCache, ApolloProvider, createHttpLink, from } from '@apollo/client'
import Context from './Context'
import { setContext } from '@apollo/client/link/context'
import { onError } from '@apollo/client/link/error'

const httpLink = createHttpLink({
  uri: 'https://petgram-server-eli.elizabethriver.vercel.app/graphql'
})

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = window.sessionStorage.getItem('token')
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : ''
    }
  }
})

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
  onError: onError(({ networkError }) => {
    if (networkError && networkError.result.code === 'invalid_token') {
      window.sessionStorage.removeItem('token')
      window.location = '/user'
    }
  })
})

ReactDOM.render(
  <Context.Provider>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </Context.Provider>
  , document.getElementById('app')
)

si llegaron hasta este punto y quieren algo de documentacion actual y ahorarse un par de horitas https://www.apollographql.com/docs/react/networking/advanced-http-networking/#customizing-request-logic

Así me quedó usando ladocumentación actualizada de @apollo/client:

import React from "react";
import ReactDOM from "react-dom";
import {
  ApolloClient,
  ApolloProvider,
  createHttpLink,
  InMemoryCache,
} from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { App } from "./App";
import Context from "./Context";

const httpLink = createHttpLink({
  uri: "localhost:3500/graphql",
});

const authLink = setContext((_, { headers }) => {
  const token = sessionStorage.getItem("token");
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

ReactDOM.render(
  <Context.Provider value={{ isAuth: true }}>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </Context.Provider>,
  document.getElementById("app")
);

Un JWT se conforma de 3 partes:

Header: Es un objeto que define qué algoritmo y tipo tiene el token.
Payload: La información que almacenamos en el token.
Verify Signature: Una encriptación del header más el payload más tu llave secreta.
Para utilizar nuestro JWT necesitamos añadirlo al header authorization de las peticiones HTTP que hagamos con el texto Bearer [token].

Esta es mi solucion para configurar el cliente de ApolloClient

  1. Instale las siguientes dependencias: npm i node-fetch apollo-link-context
  2. Cree una carpeta llamada: config, dentro de ella cree un archivo llamado: apollo.js y realize lo siguiente:

Al parecer apollo cambio la manera de escribir en el setContext, ese metodo ya no me funciona, si podrian ayudar porque nose como se estara implementando ahora.

Cual es la diferencia entre el localStorage y el SessionStorage?

Tuve problemas con mi aplicación ya que en el formulario de iniciar sesión y en el formulario de crear cuenta, estaba usando un hook llamado “useLocalStorage”.
.
Para guardar en localStorage y leer información de localStorage, la información debe ser parseada a JSON y para leerla debe ser “stringifyteada” de JSON a String, aprendí en esta clase que el sessionStorage no necesita este proceso (creo?).
.
¿Qué estaba pasando?
Podía crear la cuenta de mi usuario, y podía iniciar sesión. Pero, al momento de dar like con mi usuario, la aplicación me indicaba error, que el token era invalido. Tras revisar varias veces mi código, se me ocurrió visitar las herramientas del desarrollador de Chrome y en el header estaba la respuesta.
.
La solicitud “authorization” estaba de la siguiente manera: Bearer "40d83usdje0923....." cuando, el authorization debía viajar de la siguiente manera: Bearer 40d83usdje0923..... … ¿Ves cómo mi token era un String? Ese era el problema.
.
¿Cómo lo solucioné?
Simplemente modifiqué mi hook de useLocalStorage para pasarlo a useSessionStorage, adicionalmente tuve que cambiar su implementación en el contexto de la app para acomodar su nombre unicamnete.
Ahora el hook, me quedó de la siguiente manera:
.
hooks/useSessionStorage.js

import { useState } from 'react'

function useSessionStorage(key, initValue) {
  const [storedValue, setValue] = useState(() => {
    try {
      const item = window.sessionStorage.getItem(key)
      return item !== null ? item : initValue
    } catch (error) {
      console.error(error)
      return initValue
    }
  })

  const setSessionStorage = value => {
    try {
      window.sessionStorage.setItem(key, value)
      setValue(value)
    } catch (error) {
      console.error(error)
    }
  }

  return [storedValue, setSessionStorage]
}

export default useSessionStorage

asi me quedo

import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App'
import { ApolloProvider, ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
import Context from './Context'
import { onError } from '@apollo/client/link/error'

const httpLink  = createHttpLink ({
  uri: 'https://api-nine-gamma.vercel.app/graphql'
});

const authLink = setContext ((_, { headers }) => { // get the authentication token from local storage if it exists
  const token = window.sessionStorage.getItem('token') // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    }
  }
});


const client = new ApolloClient({

  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),

  onError: onError(
    ({ networkError }) => {
      if (networkError && networkError.result.code === 'invalid_token') {
        window.sessionStorage.removeItem('token')
        window.location.href = '/'
      }
    } 
  )

})


ReactDOM.render(
  <Context.Provider>
      <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </Context.Provider>,
  document.getElementById('app') 
)



// https://www.apollographql.com/docs/react/networking/authentication/
// https://www.apollographql.com/docs/react/networking/advanced-http-networking/#customizing-request-logic

Esto esta funcionando perfectamente en Mayo 2021

Tuve que poner Bearer en mayúsculas la primera letra, no me funcionaba en minúsculas, salía usuario no encontrado.

import ApolloClient from "apollo-boost";
import { ApolloProvider } from "@apollo/react-hooks";

const client = new ApolloClient({
  uri: "https://petgram-ianpedraza-hs26ht9s0-ianpedraza.vercel.app/graphql",
  request: (operation) => {
    const token = window.sessionStorage.getItem("token");
    const authorization = token ? `Bearer ${token}` : "";
    operation.setContext({
      headers: {
        authorization,
      },
    });
  },
  onError: (error) => {
    const { networkError } = error;
    if (networkError && networkError.result.code === "invalid_token") {
      window.sessionStorage.removeItem("token");
      window.location.href = "/";
    }
  },
});

Me salio error de Apollo Client que no estaba registrado, lo que pude notar era que al registrar un nuevo usuario me logeaba de una, esto hacia que el token solo estuviera en registrar y no iniciar sesión.
Lo pude solucionar registrando por GraphQL e iniciando sesión por la aplicación y no me volvio a generar ese error

Todo un manejo de login controlado y estable, está lindo

Hola Devs:
-Les recomiendo si desean leer mas sobre JWT (JSON Web Tokens), les dejo una muy buena lectura: JWT
Recuerden, #NuncaParesDeAprender 💚

Encontré esta informacion sobre los JWT vale la pena leerla

Autenticando una API con JWT

mi código de index usando @apollo/client

import React from 'react'
import ReactDOM from 'react-dom'

// Graph QL Imports
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { ApolloProvider } from '@apollo/react-hooks'
import { setContext } from '@apollo/client/link/context'

import App from './App'

//  Global State
import Context from './Context'

const httpLink = new createHttpLink({
  uri: 'https://pixtagram-server.vercel.app/graphql',
})

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = sessionStorage.getItem('token')
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : '',
    },
  }
})

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
})

ReactDOM.render(
  <Context.Provider>
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </Context.Provider>,
  document.getElementById('app')
)

Tomando el reto se agrega solo bloqueo a feature photoCardsDetails

export const App = () => {
  return (
    <div>
      <GlobalStyles />
      <Logo />
      <Router>
        <Home path='/' />
        <Home path='/pet/:categoryId' />
      </Router>
      <Context.Consumer>
        {
          ({ isAuth }) =>
            isAuth
              ? (
                <Router>
                  <Detail path='/detail/:detailId' />
                  <Favorite path='/favorite' />
                  <User path='/user' />
                </Router>
              )
              : (
                <Router>
                  <NotRegisterUser path='/detail/:detailId' />
                  <NotRegisterUser path='/favorite' />
                  <NotRegisterUser path='/user' />
                </Router>
              )
        }
      </Context.Consumer>
      <NavBar />
    </div>
  )
}

configuracion apollo

Wow!
Muy interesante el tema de JWT
Ahora me dan ganas de estudiar backend jaja

n

Hola, les dejo el link de mi repositorio, hecho hasta ahora en Nextjs:
https://github.com/danyel117/petgram-platzi/tree/login

genial!!