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

Persistiendo datos en Session Storage

38/50
Recursos

De momento nuestra sesión se pierde cada que refrescamos nuestra aplicación, vamos a persistir la sesión utilizando window.sessionStorage dentro de nuestro método activateAuth, quedando:

activateAuth: token => {
	setIsAuth(true)
	window.sessionStorage.setItem('token', token)
}

Aportes 24

Preguntas 2

Ordenar por:

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

Diferencias localStorage Vs sessionStorage
la única diferencia notable es que la data almacenada en localStorage persiste para siempre o hasta ser borrada manualmente, mientras sessionStorage persiste hasta que culmine la sesión, puede ser por un tiempo determinado o hasta que se cierre el navegador.

Porque al agregar el valor inicial en useState lo hacemos con una función y no lo hacemos directamente así:

const [isAuth, setIsAuth] = useState(window.sessionStorage.getItem(‘token’))

?

Hola Devs:
-Aqui les tengo una lectura sobre LocalStorage y SessionStorage:
Click Aqui
Recuerden, #NuncaParesDeAprender 💚

tenia meses que quería saber como se persistía la sesión y ahora es solo con una lineal de código xd
chale buenísimo el curso!

Aqui mis apuntes:

---- Persistiendo datos en Session Storage ----
De momento nuestra sesión se pierde cada que refrescamos nuestra aplicación, vamos a persistir la sesión utilizando window.sessionStorage dentro de nuestro método activateAuth, quedando:

// Context.js | dentro de value

activateAuth: (token) => {
	setIsAuth(true)
	window.sessionStorage.setItem('token', token)
}

// NotRegisteredUser.js
Cambiamos la manera en la que leemos el Context y hacemos uso del hook useContext(Context)
const value = useContext(Context) devuelve el valor de contexto actual.

import React, { useContext } from 'react'
const { activateAuth } = useContext(Context)

// Context.js | exportamos el contexto

export const Context = createContext()

Usando los hooks de @apollo/client me quedo mucho más simple aún:

import React, { Fragment, useContext } from "react";
import { Context } from "../Context";
import { UserForm } from "../components/UserForm";
import { useRegisterMutation } from "../containers/RegisterMutation";
import { useLoginMutation } from "../containers/LoginMutation";

export const NotRegisteredUser = () => {
    const { activateAuth } = useContext(Context);
    const {
        registerMutation,
        loading: loadingReg,
        error: errorReg,
    } = useRegisterMutation();
    const {
        loginMutation,
        loading: loadingLog,
        error: errorLog,
    } = useLoginMutation();
    
    const onSubmitReg = ({ email, password }) => {
        const input = { email, password };
        const variables = { input };
        registerMutation({ variables }).then((data) => {
            const { signup } = data.data;
            activateAuth(signup);
        });
    };

    const onSubmitLog = ({ email, password }) => {
        const input = { email, password };
        const variables = { input };
        loginMutation({ variables }).then((data) => {
            const { login } = data.data;
            console.log(login);
            activateAuth(login);
        });
    };

    const errorMsgReg = errorReg && "ha ocurrido un error";
    const errorMsgLog =
        errorLog &&
        "el usuario o contraseña no son correctos o el usuario no existe";

    return (
        <Fragment>
            <UserForm
                error={errorMsgReg}
                loading={loadingReg}
                title="Registrarse"
                onSubmit={onSubmitReg}
            />
            <UserForm
                error={errorMsgLog}
                loading={loadingLog}
                title="Iniciar sesión"
                onSubmit={onSubmitLog}
            />
        </Fragment>
    );
};

Así me quedo, usando Hooks para las mutations.

import React, { Fragment, useContext } from 'react'
import { Context } from '../Context'
import { UserForm } from '../components/UserForm'
import { useRegisterMutation } from '../hooks/useRegisterMutation'
import { useLoginMutation } from '../hooks/useLoginMutation'

export const NotRegisteredUser = () => {
  const { register, data: dataReg, error: errorReg, loading: loadingReg } = useRegisterMutation()
  const { login, data: dataLog, error: errorLog, loading: loadingLog } = useLoginMutation()
  const { activateAuth } = useContext(Context)
  
  const registerSubmit = (email, password) => {
    register(email, password)
      .then(({ data }) => {
        const { signup } = data
        activateAuth(signup)
      })
      .catch((err) => {
        console.log('El usuario ya existe o hay algún problema.')
      })
  }
  const errorRegMsg = errorReg && 'El usuario ya existe o hay algún problema.'
  
  const loginSubmit = (email, password) => {
    login(email, password)
      .then(({ data }) => {
        const { login } = data
        activateAuth(login)
      })
      .catch((err) => {
        console.log('La contraseña no es correcta o el usuario no existe.')
      })
  }
  const errorLogMsg = errorLog && 'La contraseña no es correcta o el usuario no existe.'

  return (
    <Fragment>
      <UserForm disabled={loadingReg} error={errorRegMsg} title='Registrarse' onSubmit={registerSubmit} />
      <UserForm disabled={loadingLog} error={errorLogMsg} title='Iniciar sesión' onSubmit={loginSubmit} />
    </Fragment>
  )
}

Mi versión utilizando un custom hook:

import React, { createContext, useState } from 'react'

import { useSesionStorage } from './hooks'

export const StoreContext = createContext()

export default ({ children }) => {
  const [token, setToken] = useSesionStorage('token', '')
  const [isAuth, setIsAuth] = useState(token)

  const store = {
    isAuth,
    activateAuth: token => {
      setToken(token)
      setIsAuth(true)
    }
  }

  return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
}

En el Context.js se tienen dos export. Uno en donde exporta el Context y otro en donde exporta el Consumer y el Provider de manera separada. No me gusta mucho como se ve, ¿existe alguna otra alternativa para hacer lo mismo pero exportando solo uno?

En clases anteriores habiamos creado un hook para persistir datos en el localStorage, me pareció practico reusarlo. Mi contexto quedo así:

import React, { useState, createContext, useContext } from 'react'
import { useLocalStorage } from './hooks/useLocalStorage'

const Context = createContext(null)

export const ContextProvider = ({ children }) => {
  const [token, setToken] = useLocalStorage('token', '')
  const [isLogged, setIsLogged] = useState(() => !!token)

  const toggleAuth = (token) => {
    if (!token || typeof token !== 'string') {
      setIsLogged(false)
      return
    }

    setToken(token)
    setIsLogged(true)
  }

  return (
    <Context.Provider value={{ isLogged, token, toggleAuth }}>
      {children}
    </Context.Provider>
  )
}

export const usePetgramContext = () => {
  return useContext(Context)
}

y NotRegisterUser.js quedó así:

import React, { useState } from 'react'
import { usePetgramContext } from '../Context'
import { UserForm } from '../components/UserForm'
import { useGraphQl } from '../hooks/useGraphQl'

export const NotRegisterUser = () => {
  const { toggleAuth } = usePetgramContext()
  const [registerError, setRegisterError] = useState(null)
  const [loginError, setLoginError] = useState(null)
  const [loading, setLoading] = useState(false)
  const [register, login] = useGraphQl()

  const onRegister = async ({ email, password }) => {
    setLoading(true)
    try {
      const response = await register({ variables: { input: { email, password } } })
      toggleAuth(response.data.signup)
    } catch {
      setRegisterError('El usuario ya existe o hay algún problema')
    } finally {
      setLoading(false)
    }
  }

  const onLogin = async ({ email, password }) => {
    setLoading(true)
    try {
      const response = await login({ variables: { input: { email, password } } })
      toggleAuth(response.data.login)
    } catch {
      setLoginError('Valida que las credenciales sean correctas')
    } finally {
      setLoading(false)
    }
  }

  return (
    <>
      <UserForm disabled={loading} error={registerError} title='Registrarse' onSubmit={onRegister} />
      <UserForm disabled={loading} error={loginError} title='Iniciar sesión' onSubmit={onLogin} />
    </>
  )
}

Hola, les dejo el repositorio con el avance de mi proyecto hecho en Nextjs:
https://github.com/danyel117/petgram-platzi/tree/login

Por alguna razon no se ve reflejado los datos que estoy guardando al servidor NOW.SH.

Como si solo guardara en el localStorage y a la hora de limpiar el cache se va todos los usuarios ya creados.

¿Porque será?

Hola Miguel, saludos

Es buena practica escribir muchas valores en el contexto y tratar de canalizar la gran parte por el contexto y no por props, o estados locales?

Tengo una duda no sé si alguien puede responderme…
porque dentro del onSubmit del registrar el activateAuth va sin paréntesis:

const onSubmit = ({email, password}) => {
                        const input = { email, password }
                        const variables = { input }
                        register({ variables })
                        .then(activateAuth)
                    }

y dentro del obSubmitLogin si va el activateAuth con paréntesis?

const onSubmitLogin = ({ email, password }) => {
                        const input = { email, password }
                        const variables = { input }
                        login({ variables })
                        .then(response => {
                            console.log(response);
                            activateAuth()
                        })
                      }

No entiendo la necesidad de crear una funcion para recuperar el token, yo simplremente llame la funcion getItem y la guarde en una constante;

const isToken = window.sessionStorage.getItem('token')
const [isAuth, setIsAuth] = useState(isToken)

Hola, no entiendo cómo al exportar el context y hacer uso de useContext() sigue funcionando todo al igual que lo hacía antes. ¿Cómo puede acceder a la información y cómo sabe que se quiere acceder al consumer? Me imagino que es porque sigue el export default de todo el contexto. Pero no me queda claro cómo se hace un export nombrado de createContext() de React directamente y se tiene acceso a toda la información. ¿Alguien podría explicar esto un poco más?

Mi context

import React, { createContext, useContext, useReducer } from 'react';

export const StateContext = createContext();

// eslint-disable-next-line react/prop-types
export const StateProvider = ({ reducer, initialState, children }) => (

  <StateContext.Provider value={useReducer(reducer, initialState)}>
    {children}
  </StateContext.Provider>
);

export const useStateValue = () => useContext(StateContext);

El client debe ser creado diferente según la documentación de apollo, para hacerlo como esta abajo hace falta tambien instalar las librerías que aparecen en los imports.

import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient } from 'apollo-boost'
import { ApolloProvider } from '@apollo/react-hooks'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { createHttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import { App } from './App'
import * as serviceWorker from './serviceWorker'
import Context from '../src/Context'

const httpLink = createHttpLink({
  uri: 'https://petgram-server-dfarcos.dariofelipearcos.now.sh/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')
)

Mi progreso hasta ahora.
https://petgram.jacksonduvan.now.sh/

queda mucho mejor el Context con el Hook useContext, este no se puede usar en Class Functions cierto?

Porque aqui retorna el token?

const [isAuth, setIsAuth] = useState(() => {
    return window.sessionStorage.getItem('token')
  })```


😕