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

Mutaciones para iniciar sesión

37/50
Recursos

Aportes 38

Preguntas 3

Ordenar por:

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

El progreso de la app.

Muy bien!! Este curso es uno de los mejores que he tomado en Platzy!

Excelente curso!
Asi va la pantalla de Inicio de Sesion y registro

Agrege un loader al lado del boton de cada formulario, para dar un mejor feedback

utilizando useMutation( )

NotRegisterUser

import React from 'react'
import { UserForm } from '../components/UserForm'
import { useRegisterMutation } from '../container/RegisterMutation'
import { useLoginMutation } from '../container/LoginMutation'
import { useAuthContext } from '../context'

export const NotRegisterUser = () => {
  const { activateUser } = useAuthContext()
  const { register, loading: loadingRegister, error: errorRegister } = useRegisterMutation()
  const { login, loading: loadingLogin, error: errorLogin } = useLoginMutation()
  const onSubmitRegister = ({ email, password }) => {
    const input = { email, password }
    const variables = { input }
    register({ variables }).then(res => {
      console.log(res)
      activateUser()
    }).catch(err => {
      console.log(err)
    })
  }
  const onSubmitLogin = ({ email, password }) => {
    const input = { email, password }
    const variables = { input }
    login({ variables }).then(res => {
      console.log(res)
      activateUser()
    }).catch(err => {
      console.log(err)
    })
  }
  const errorMsg = errorRegister && 'El usuario ya existe o hay algun problema'
  const errorLoginMsg = errorLogin && 'El usuario no existe o hay algun problema'
  return (
    <>
      <UserForm onSubmit={onSubmitRegister} title='Registrarse' error={errorMsg} disabled={loadingRegister} />
      <UserForm onSubmit={onSubmitLogin} title='Iniciar Sesion' error={errorLoginMsg} disabled={loadingLogin} />
    </>
  )
}

LoginMutation

import { gql, useMutation } from '@apollo/client'
const LOGIN_MUTATION = gql`
  mutation login($input: UserCredentials!) {
    login (input: $input)
}
`
export const useLoginMutation = () => {
  const [login, { loading, error }] = useMutation(LOGIN_MUTATION)
  return { login, loading, error }
}

RegisterMutation

import { gql, useMutation } from '@apollo/client'
const REGISTER_MUTATION = gql`
  mutation signup($input: UserCredentials!) {
    signup (input: $input)
  }
`
export const useRegisterMutation = () => {
  const [register, { loading, error }] = useMutation(REGISTER_MUTATION)
  return { register, loading, error }
}

Con los hooks de apollo es posible resolví realizar los mutation de esta manera:

import { useMutation } from 'react-apollo-hooks'
import gql from 'graphql-tag'

const REGISTER = gql`
  mutation signup($input: UserCredentials!) {
    signup(input: $input)
  }
`

export const useRegisterMutation = (email, password) => {
  const [mutation, { data, error, loading }] = useMutation(REGISTER)
  const registerUser = (email, password) => {
    mutation({ variables: { input: { email, password } } })
  }
  return { registerUser, data, error, loading }
}
import { useMutation } from 'react-apollo-hooks'
import gql from 'graphql-tag'

const LOGIN = gql`
  mutation login($input: UserCredentials!) {
    login(input: $input)
  }
`

export const useLoginMutation = (email, password) => {
  const [mutation, { data, error, loading }] = useMutation(LOGIN)
  const loginUser = (email, password) => {
    mutation({ variables: { input: { email, password } } })
  }
  return { loginUser, data, error, loading }
}

Y en el NotRegisteredUser quedaría de esta forma:

import React 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 { registerUser, data: dataReg, error: errorReg, loading: loadingReg } = useRegisterMutation()
  const { loginUser, data: dataLog, error: errorLog, loading: loadingLog } = useLoginMutation()

  const errorMsgReg = errorReg && 'El usuario ya existe o hay algún problema'
  const errorMsgLog = errorLog && 'La contraseña no es correcta o el usuario no existe'

  if (dataReg || dataLog) {
    console.log(dataLog)
    return (
      <Context.Consumer>
        {({ isAuth, activateAuth }) => activateAuth() }
      </Context.Consumer>
    )
  }

  return (
    <>
      <UserForm error={errorMsgReg} disabled={loadingReg} onSubmit={registerUser} title='Registrarse' />
      <UserForm error={errorMsgLog} disabled={loadingLog} onSubmit={loginUser} title='Iniciar sesión' />
    </>
  )
}

Mi solucion con react hook:

loginUsuario.js

import { gql, useMutation } from '@apollo/client'

const LOGIN = gql`
mutation login($input: UserCredentials!){
    login (input: $input)
}
`

export const useLoginMutation = () => {
    const [loginMutation, { data, loading, error }] = useMutation(LOGIN);
    return {
        loginMutation,
        dataLogin: data,
        loadingLogin: loading,
        errorLogin: error
    }
}

NotRegisteredUser.js

import React from 'react'
import Context from '../Context'
import { UserForm } from '../components/user_form'
import { useRegisterMutation } from '../hoc/registrarUsuario'
import { useLoginMutation } from '../hoc/loginUsuario'

export const NotRegisteredUser = () => {

    const { registerMutation, data, loading, error } = useRegisterMutation()
    const { loginMutation, dataLogin, loadingLogin, errorLogin} = useLoginMutation()

    return (
        <Context.Consumer>
            {
                ({ activateAuth }) => {
                    const onSubmit = ({ email, password }) => {
                        const input = { email, password }
                        const variables = { input }
                        registerMutation({ variables }).then(activateAuth)
                    }

                    const onSubmitLogin = ({ email, password }) => {
                        const input = { email, password }
                        const variables = { input }
                        loginMutation({ variables }).then(activateAuth)
                    }

                    const errorMsg = error && 'El usuario ya existe o hay algún problema.'
                    const errorLoginMsg = errorLogin && 'El usuario o la contraseña están errados.'

                    return (
                        <React.Fragment>
                            <UserForm onSubmit={onSubmit} title='Registrarse' error={errorMsg} disabled={loading} />
                            <UserForm onSubmit={onSubmitLogin} title='Iniciar sesión' error={errorLoginMsg} disabled={loadingLogin} />
                        </React.Fragment>
                    )
                }
            }
        </Context.Consumer>
    )
}

Tengo un problema de CORS que no puedo solucionar.
Access to fetch at ‘https://instapet-server-hzxo40qb3.now.sh/graphql’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
Parece que GraphQL me da el problema. Ya revise en la API y esta definido el middleware de uso de cors.

Aqui les dejo mi codigo con hooks.

//LoginMutation.js
import { gql, useMutation } from ‘@apollo/client’

const LOGIN = gqlmutation login($input: UserCredentials!){ login(input: $input) }
export const useLoginMutation = () => {
const [loginMutation, dataLogin] = useMutation(LOGIN)

return { loginMutation, dataLogin}
}

//RegisterMutation.js
import { gql, useMutation } from ‘@apollo/client’

const REGISTER = gqlmutation signup($input: UserCredentials!){ signup(input: $input) }
export const useRegisterMutation = () => {
const [registerMutation, dataRegister] = useMutation(REGISTER)

return { registerMutation, dataRegister}
}

//NotRegisteredUser.js

import React, { Fragment } from 'react’
import Context from '…/Context’
import { UserForm } from '…/components/UserForm’
import { useRegisterMutation } from '…/hooks/RegisterMutation’
import { useLoginMutation } from ‘…/hooks/LoginMutation’

export const NotRegisteredUser = () => {
const { registerMutation, dataRegister } = useRegisterMutation()
const errorRegister = dataRegister.error?.graphQLErrors[0].message

const { loginMutation, dataLogin } = useLoginMutation()
const errorLogin = dataLogin.error?.graphQLErrors[0].message

console.log(dataLogin)

return (
    <Context.Consumer>
        {
            ({activateAuth}) => {
                const onSubmit = ({email, password}) => {
                    const input = { email, password }
                    const variables = { input }
                    registerMutation({ variables })
                    .then(activateAuth)
                }
                const loginAction = ({email, password}) => {
                    const input = { email, password }
                    const variables = { input }
                    loginMutation({ variables })
                    .then(activateAuth)
                }
                
                return <>
                    <UserForm disabled={dataRegister.loading} error={errorRegister} onSubmit={onSubmit} title='Registrarse'/>
                    <UserForm disabled={dataLogin.loading} error={errorLogin} onSubmit={loginAction} title='Iniciar Sesion'/>
                </>
            }
        }
    </Context.Consumer>
)

}

Asi voy. Que curso tan bueno.

El avance en mi proyecto:

Petgram

Super este curso, hasta el momento me ha parecido muy bueno no tengo inconvenientes muchas gracias, dejo mi github para que puedan ver lo que se leva hasta el momento https://github.com/AngieGarcia1989/React-avanzado/commit/9af2ea404af4fed9925e3f000feeacab339d60b6

💚

Este es el progreso del app, jeje la personalicé un poco:

Home:

Login:

Así va quedando mi aplicación!

Pantalla de Login

Pantalla de registro

A nivel de código no estoy utilizando la metodología de render props, sino, que estoy haciéndolo con los hooks de React Apollo, y los tengo de la siguiente manera:

Y así lo consumo en los componentes de signup y login

Por cierto, cuando loading es true devuelvo un loader que se ve de la siguiente forma:

Avance, implemente un loading en el botón validando si la prop de loading esta activa.

Les comparto lo que tengo hecho hasta ahora!

Al iniciar sesión si no relleno ningún campo me lo valida y entra en la app como usuario registrado 😅 ¿Puede ser que esto pase porque quizás le haya dado al botón de registrarse sin rellenar ningún campo? 🤔

Mi avance:

Realizado con hooks

UnregisteredUser.jsx

/* eslint-disable react/jsx-props-no-spreading */
import React from 'react';

import { TiArrowBackOutline } from 'react-icons/ti';
import { P, Button, Icon } from './styles';

import UserForm from '../../components/UserForm/index';
import { useStateValue } from '../../Context';
import useRegisterMutation from '../../hooks/useRegisterMutation';
import useLoginMutation from '../../hooks/useLoginMutation';

const useMutationValue = (action, loading, error, type, errorMsg) => ({
  action, loading, error, type, errorMsg,
});

const UnregisteredUser = () => {
  const [{ sectionLogin, email, password }, dispatch] = useStateValue();
  const {
    register, data, loading, error,
  } = useRegisterMutation(email, password);

  const {
    Login, dataLogin, loadingLogin, errorLogin,
  } = useLoginMutation(email, password);

  const REGISTER = useMutationValue(register, loading, error, 'sectionLogin', 'El usuario ya existe o ha ocurrido algún otro problema');
  const LOGIN = useMutationValue(Login, loadingLogin, errorLogin, 'UpdateUserLogin', 'La contraseña no es correcta o el usuario no existe');
  const handleOnCLickValue = (boolean) => {
    dispatch({
      type: 'sectionLogin',
      payload: boolean,
    });
  };

  return (
    <>
      {sectionLogin
        ? (
          <>
            <UserForm title="Iniciar sesión" {...LOGIN} />
            <P>
              ¿ No tienes una cuenta ?
              <Button type="submit" onClick={() => handleOnCLickValue(false)}>REGISTRARSE</Button>
            </P>
          </>
        )
        : (
          <>
            <UserForm title="Registrarse" {...REGISTER} />
            <Icon type="submit" onClick={() => handleOnCLickValue(true)}><TiArrowBackOutline size="30px" /></Icon>
          </>
        )}
    </>

  );
};


export default UnregisteredUser;

Progreso del app, pestaña NotRegister para rutas que validen autenticación.

sign up failed:

sign in

Puedes acceder a la aplicación dando clic aquí.

![](

Actualizacion apollo client 2021

Mi solución en LoginMutation.js

Saludos. 💚😀

import React from 'react'
import { gql } from '@apollo/client'
import { Mutation } from '@apollo/client/react/components'

const LOGIN = gql`
mutation login($input: UserCredentials!) {
  login (input: $input)
}
`
export const LoginMutation = ({ children }) => {
  return (
    <Mutation mutation={LOGIN}>
      {children}
    </Mutation>
  )
}

Lo estoy manejando un poco diferente, como ambos formularios son similares, lo que hago es que en el UserForm se ejecute la mutación enviándola como prop desde el NotRegisterUser.
las mutaciones las obtengo de unos customHooks muy similar a unos comparñeros en clases anteriores.
Les comparto cómo lo hice 😃

NotRegisterUser:

import React, { useState } from 'react'
import { UserForm } from '../components/UserForm'
import { useMutationSignin, useMutationSignup } from '../hooks/mutations'

export const NotRegisterUser = () => {

  const [registred, setRegistred] = useState(false)
  const { mutationSignin } = useMutationSignin()
  const { mutationSignup } = useMutationSignup()

  return (
    <>
    {
      registred 
      ? <Section>
          <UserForm title='Login' mutation={mutationSignup}/>
          <p>¿No tienes cuenta? 
            <Button onClick={() => setRegistred(!registred)}>Regístrate</Button>
          </p>
        </Section>
      : <Section>
        <UserForm title='Registrarse' mutation={mutationSignin}/>
        <p>¿Ya tienes una cuenta?
          <Button onClick={() => setRegistred(!registred)}>Inicia sesión</Button>
        </p>
      </Section>
    }
    </>
  )
}

el UserForm:

import React, { useContext, useState } from 'react'
import { AppContext } from '../../context/Appcontext'
import { useHistory } from 'react-router'

import { useInputValue } from '../../hooks/useInputValue'
import { Button, Form, Input, Title } from './styles'

export const UserForm = ({title, mutation}) => {
  const email = useInputValue('')
  const password = useInputValue('')
  const [loading, setLoading] = useState(false)
  const [submitError, setSubmitError] = useState(false)
  const [textError, setTextError] = useState('')
  const { login } = useContext(AppContext)
  const history = useHistory()

  const handleSubmit = (e) => {
    e.preventDefault()
    mutation({
      variables: {
        input: {
          email: email.value,
          password: password.value
        }
      }
    }).then(res => {
      setLoading(false)
      login()
      history.push('/user')
    }).catch(err => {
      setLoading(false)
      console.log({errSignup: err.message})
      setSubmitError(true)
      setTextError(err.message)
    })
  }

  return (
    <>
      <Title>{title}</Title>
      <Form onSubmit={handleSubmit}>
        <Input disabled={loading} type="text" placeholder='Email' {...email} />
        <Input disabled={loading} type="password" placeholder='Password' {...password} />
        <Button disabled={loading}>{title}</Button>
      </Form>
      {
        loading && <span>Espere... <br /></span>
      }
      {
        submitError && <AlertMessage>{textError} <br /></AlertMessage>
      }
    </>
  )
}

Excelente, mi progreso es tal cual llevas la aplicación a este video

Vamos excelente, está quedando genial la aplicación:

Mi progreso hasta el momento: https://github.com/behagoras/petgram/tree/login/register

Mi resultado final: https://petgram.behagoras.now.sh/favs

Mi proyecto

Entendiendo mucho y mejorando mis conocimientos de React

hasta el momento todo me ha parecido super increible el profe es un duro… tengo un problema al hacer el deploy me aparece el siguiente error
agradeceria si alguien me puede colaborar
gracias!!

Voy entendiendo todo, confieso que debo esforzarme mas en los estilos, no he aportado mi lado creativo

Mi solución con react hooks, implementada en el componente userForm y he creado un hook que en función del title del formulario hace una petición de registro o login.

Es un poco barata pero funciona correctamente y sin repetir mucho código:

El Hook:

import { useMutation } from '@apollo/react-hooks'
import { gql } from 'apollo-boost'

const REGISTER = gql`
  mutation signup($input: UserCredentials!) {
    signup(input: $input)
  }
`

const LOGIN = gql`
  mutation login($input: UserCredentials!) {
    login(input: $input)
  }
`

const useFormToDB = (title) => {
  if (title === 'Register') {
    const [method, { data, loading, error }] = useMutation(REGISTER)
    return { method, data, loading, error }
  }
  if (title === 'Login') {
    console.log('try to login')
    const [method, { data, loading, error }] = useMutation(LOGIN)
    return { method, data, loading, error }
  }
}

export default useFormToDB

Componente userForm:

import React, { useState } from 'react'

import { useInputValue } from '../../hooks/useInputValue'
import { Form, Input, Button, Title, Error, Loader } from './styles'

import loader from '../../assets/images/loader.gif'

// Register Hook
import useFormToDB from '../../hooks/useFormToDB'

const UserForm = ({ onSubmit, title }) => {
  const [errorForm, setErrorForm] = useState('')
  const [disabled, setDisabled] = useState(false)

  const { method, data, loading, error } = useFormToDB(title)

  const email = useInputValue('')
  const password = useInputValue('')

  const handleSubmit = async (e) => {
    e.preventDefault()

    try {
      setDisabled(true)
      await method({
        variables: {
          input: {
            email: email.value,
            password: password.value,
          },
        },
      })
      setDisabled(false)
      onSubmit()
    } catch (error) {
      setDisabled(false)
      setErrorForm(error)
    }
  }

  const errorMsg = error && 'Error test'
  return (
    <>
      <Title>{title}</Title>
      <Form onSubmit={handleSubmit}>
        <label>Email</label>
        <Input
          disabled={disabled}
          placeholder="Email"
          {...email}
          type="email"
        />
        <label>Password</label>
        <Input
          disabled={disabled}
          placeholder="Password"
          {...password}
          type="text"
        />
        {errorForm && (
          <Error>
            {title === 'Register'
              ? 'Your mail is already registered'
              : 'Email or password incorrect'}
          </Error>
        )}
        <Button type="submit" disabled={disabled}>
          {loading ? <Loader src={loader} /> : <span>{title}</span>}
        </Button>
      </Form>
    </>
  )
}

export default UserForm

hola dejo mi codigo para los que les gustarian usar async await en LoginMutation
primero agrega
import ‘babel-polyfill’(lo agrega en NotRegisteredUser.js) despues
npm i -D babel-polyfills (lo instala )

<LoginMutation>
{
(login, { error, data, loading }) => { // el orden de los datos que retornan no perjudican en nada
const onSubmit = ({ email, password }) => {
const variables = { input: { email, password } }
const vlor = async ({ variabl }) => {
const resultado = await login({ variables })
return resultado
}
vlor(variables).then(activateAuth)
}
const errorMsg = error && 'el usuario ya existe hay un problema’
return <UserForm disable={loading} error={errorMsg} title=‘Iniciar Session’ onSubmit={onSubmit} />
}
}
</LoginMutation>

Hola Devs:
-Espero que a todos los que hayan llegado hasta aqui les vaya encantado todo lo que van aprendiendo y sobre todo con el gran maestro que tenemos aqui, aprovechemos todos esta oportunidad de tener a un maestro super preparado y que sabe muy bien de lo que habla.
Aqui les comparto mi progreso:

Recuerden, #NuncaParesDeAprender 💚

Bueno, tengo todo el codigo pero me genera error desde la primera clase. 😦

Les dejo el avance de mi proyecto, hecho en Nextjs:

https://github.com/danyel117/petgram-platzi/tree/login

Hola, comparto mi versión del registro y login con @apollo-client que incluye los hooks:

<h1>hooks/useLogin.js</h1>

import { gql, useMutation } from '@apollo/client'

const LOGIN = gql`mutation login($input: UserCredentials!) {
  login(input: $input)
}`

export const useLogin = () => {
  const [mutation, {
       data, 
       loadingLogin, 
       error
  }] = useMutation(LOGIN)
  
 function handleLogin({ email, password }) {
    return mutation({ variables: { input : { 
        email,
        password
     } } })
  }
   
  const errorLogin = error && 'No se puede iniciar sesión. El usuario no existe o el password no es correcto.'
  
  return {
    handleLogin,
    data,
    loadingLogin,
    errorLogin
   }
}

<h1>pages/notRegistered.js</h1>

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

export const NotRegistered = () => {
  const { activateAuth } = useContext(Context)
  const {errorLogin, loadingLogin, handleLogin} = useLogin()

  const handleLogin = (formData) => {
    handleLogin(formData)
      .then(({ data }) => activateAuth(data.login))
  }

  return (
    <Fragment>
      <UserForm 
        disabled={loadingLogin}
        error={errorLogin}
        title='Iniciar sesión'
        onSubmit={handleLogin} />
    </Fragment>
  )
}