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

Curso de React Avanzado

Curso de React Avanzado

Miguel Ángel Durán

Miguel Ángel Durán

Cerrar sesión

41/50
Recursos

Aportes 14

Preguntas 2

Ordenar por:

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

o inicia sesión.

A mi me pasaba que cuando me logueaba o cerraba sesión, no se actualizaban los datos de los likes, es decir, apollo sigue usando la cache vieja, osea que al cerrar sesión seguía viando los likes viejos, o lo mismo si cambiaba de usuario.

La solución más sencilla que encontré es exportar el objeto client de index.js, e importarlo en Context.js, para así limpiar la cache cuando cambia el estado de autenticación, ya sea si se inicia o se cierra una sesión.

También hay que borrar el estado de Apollo client al hacer logout:

  • Context.js
import { useApolloClient } from "@apollo/client";
const client = useApolloClient();
removeAuth: () => {
      setIsAuth(false);
      window.sessionStorage.removeItem("token");
      client.resetStore();
    },

Para que funcione asegurense que el Context.Provider esté dentro de Provider de Apollo:

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

El ciclo completo de una aplicación, de verdad me sorprendió este curso

Hola a todos, la fecha es 05/04/2022
Les dejo el codigo que utilice:

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

const httpLink = createHttpLink({
  uri: "https://petgram-server-max-seven.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(),
  onError: onError(({ networkError }) => {
    if (networkError && networkError.result.code === 'invalid_token') {
      window.sessionStorage.removeItem('token')
      window.location.href = '/user'
    }
  })
})

ReactDOM.render(
  <ApolloProvider client={client} >
    <AppProvider>
      <App />
    </AppProvider>
  </ApolloProvider>

, document.getElementById('app'))

import React, { createContext, useState } from 'react'
import { useApolloClient } from '@apollo/client'

const AppContext = createContext(null);

const AppProvider = (props) =>{
  const [isAuth, setIsAuth ] = useState(()=>{
    return sessionStorage.getItem('token')
  });
  const client = useApolloClient()


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

  const removeAuth = ()=>{
    setIsAuth(false)
    sessionStorage.removeItem('token')
    client.resetStore()
  }

  const value = {
    isAuth,
    activateAuth,
    removeAuth
  }

  return (
    <AppContext.Provider value ={value}>
      {props.children}
    </AppContext.Provider>
  )
}


export { AppContext, AppProvider };

import React from 'react'
import { Button } from './styles'

export const SubmitButton = ({onClick, text, disabled = false})=>{
  return (
    <Button disabled={disabled} onClick={onClick} >{text}</Button> 
  )
}

import styled from "styled-components";

export const Button = styled.button`
background: #8d00ff;
border-radius: 3px;
color: #fff;
height: 32px;
display: block;
width: 100%;
text-align: center;
&[disabled]{
  opacity: 0.3;
}
`
import React from 'react'
import { useInputValue } from '../../hooks/useInputValue'
import { SubmitButton } from '../SubmitButton'
import { Form, Input, Title, Error, Spinner } from './styles'

const UseForm = ({ onSubmit, title, error, disabled })=>{
  const email     = useInputValue('')
  const password  = useInputValue('')
  const handlerSubmit = (event)=>{
    event.preventDefault()
    onSubmit({email: email.value, password: password.value})
  }
  return (
    <>
      <Form onSubmit={handlerSubmit}>
        <Title>{title}</Title>
        <Input disabled={disabled} placeholder='email' {...email} />
        <Input disabled={disabled} placeholder='password' type='password' {...password} /> 
        <SubmitButton text={title} disabled={disabled} />
      </Form>
      {disabled && <Spinner></Spinner>}
      {error && <Error>{error}</Error>}
    </>
    
  )
}

export { UseForm }

no se si a alguien mas le pasa pero no me funciona el useContext. desde la pagina de notRegisteredUser.js he tenido que usar el metodo del Context.Consumer sino me sale un error de que context no esta definido… a alguien mas le pasa?

Faltaría solo la validación de los datos que pasamos en los formularios ya que por ejemplo hasta los momentos puedo registrar un usuario pasando datos vacíos de user y password, pero supongo que es para otro curso o aquí mismo mas adelante

No me parece que la manera de crear componentes por carpetas con sus estilos dentro sea la mejor manera de reutilizar ciertas caracteristicas

Yo utilice redux toolkit, aqui dejo mi codigo para quien hiciera lo mismo:

import { createSlice } from "@reduxjs/toolkit"

const initialState = {
  isAuth : sessionStorage.getItem('token')
}

const authSlice = createSlice({
  name: 'auth',
  initialState,
  reducers: {
    activateAuth: (state, action) => {
      sessionStorage.setItem('token', action.payload)
      state.isAuth = action.payload;
    },
    removeAuth: (state, action) =>{
      sessionStorage.removeItem('token');
      state.isAuth = false;
    }
  }
})

export const { activateAuth, removeAuth } = authSlice.actions;

export const authReducer = authSlice.reducer;

import React from 'react'
import { Button } from './styles'

export const SubmitButton = ({onClick, text, disabled = false})=>{
  return (
    <Button disabled={disabled} onClick={onClick} >{text}</Button> 
  )
}

import styled from "styled-components";

export const Button = styled.button`
background: #8d00ff;
border-radius: 3px;
color: #fff;
height: 32px;
display: block;
width: 100%;
text-align: center;
&[disabled]{
  opacity: 0.3;
}
`

import styled from "styled-components";

export const Form = styled.form`
  padding: 16px 0;
`

export const Input = styled.input`
  border: 1px solid #ccc;
  border-radius: 3px;
  margin-bottom: 8px;
  padding: 8px 4px;
  display: block;
  width: 100%;
  &[disabled]{
    opacity: 0.3;
  }
`

export const Title = styled.h2`
  font-size: 16px;
  font-weight: 500;
  padding: 8px 0;
`

export const Error = styled.span`
  font-size: 14px;
  color: red;
`
export const Spinner = styled.div`
  @keyframes spin {
    0% {
      transform: rotate(0deg);
    }
  
    100% {
      transform: rotate(360deg);
    }
  
  }
  border: 4px solid rgba(0, 0, 0, 0.1);
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border-left-color: #09f;
  margin:auto;
  animation: spin 1s ease infinite;
`

import React from 'react'
import { useInputValue } from '../../hooks/useInputValue'
import { SubmitButton } from '../SubmitButton';
import { Error, Form, Input, Spinner, Title } from './styles'

const UserForm = ({ onSubmit, title, disabled, error })=>{
  const email     = useInputValue('');
  const password  = useInputValue('');
  const handlerSubtmit = (event) =>{
    event.preventDefault();
    onSubmit({email: email.value, password: password.value});
  };
  
  return (
    <>
      <Title>{title}</Title>
      <Form onSubmit={handlerSubtmit}>
        <Input disabled={disabled} placeholder='email' {...email} />
        <Input disabled={disabled} placeholder='password' type='password' {...password} />
        <SubmitButton disabled={disabled} text={title} />
      </Form>
      {disabled && <Spinner />}
      {error && <Error>{error}</Error>}
    </>
  )
}

export { UserForm }

import React from "react"
import { SubmitButton } from "../components/SubmitButton"
import { useDispatch } from 'react-redux'
import { removeAuth } from "../store/authReducer";

export const User = ()=>{
  const dispatch = useDispatch();
  const handlerLoguot = ()=>{
    dispatch(removeAuth());
  }

  return (
    <>
      <SubmitButton text={'Cerrar sesión'} onClick={handlerLoguot} />
    </>
  )
}

Lord

Así solucioné el problema del hook de context:

import React from 'react';
import Context from '../Context';

export const User = () => {
	return (
		<Context.Consumer>
			{
				({ removeAuth }) => {
					return (
						<>
							<h1>User</h1>

							<button onClick={removeAuth}>Logout</button>
						</>
					)
				}
			}
		</Context.Consumer>
	);
};

No se si alguien mas lo nota, pero al momento de iniciar sesion y dirigirse al home no muestra las imagenes que tienen me gusta, hay que recargar la pagina para que aparezcan, como se haria para solucionar este problema? en este caso no se puede utilizar el fetchPolicy porque los likes se guardan con mutaciones

Si alguno tiene problemas con el context les dejo el que yo hice para que puedan solucinarlo.

import React, { createContext, useState } from 'react'
const Context = createContext()
const { Provider: ContextProvider, Consumer } = Context

const Provider = ({ children }) => {
  const [isAuth, setAuth] = useState(() =>
    window.sessionStorage.getItem('token')
  )
  const value = {
    isAuth,
    activateAuth: token => {
      setAuth(true)
      window.sessionStorage.setItem('token', token)
    },
    removeAuth: () => {
      setAuth(false)
      window.sessionStorage.removeItem('token')
    }
  }

  return <ContextProvider value={value}>{children}</ContextProvider>
}

export { Provider, Consumer, Context }

gracias!!!