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

Parámetros para un query con GraphQL

22/50
Recursos

Aportes 36

Preguntas 6

Ordenar por:

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

o inicia sesión.

¿Podríamos decir que:

  • M: withPhotos
  • V: ListOfPhotoCardComponent
  • C: ListOfPhotoCard

??? es un pequeño MVC del lado del cliente?

Los react hooks en apollo 😎😎😎

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

const getPhotos = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`

export const useGetPhotos = categoryId => {
  const { loading, data, error } = useQuery(getPhotos, { variables: { categoryId } })
  return { loading, data, error }
}

Estoy realizando este ejercicio utilizando hooks, @apollo/client como cliente y proveedor

En el entrypoint de la app importamos el ApolloClient, ApolloProvider de @apollo/client

/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App'
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'

const client = new ApolloClient({
  uri: process.env.API_URL,
  cache: new InMemoryCache()
})

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

El query lo separé en un custom hook

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

export function useGetPhotos (categoryId) {
  const GET_PHOTOS = gql`
    query getPhotos($categoryId: ID) {
      photos (categoryId: $categoryId){
        id
        categoryId
        src
        likes
        liked
        userId
        
      }
    }`

  const { loading, error, data } = useQuery(GET_PHOTOS, { variables: { categoryId } })

  return { loading, error, data }
}

y ListOfPhotocards.js implementa el custom hook de la forma

import React from 'react'
import { PhotoCard } from '../PhotoCard'
import { useGetPhotos } from '../../hooks/useGetPhotos'

export const ListOfPhotoCards = ({ categoryId }) => {
  const { loading, error, data } = useGetPhotos(categoryId)

  if (loading) return <p>Loading...</p>
  if (error) return <p>error...</p>

  return (
    <ul>
      {data.photos.map((photo) => (
        <PhotoCard key={photo.id} id={photo.id} {...photo} />
      ))}
    </ul>

  )
}

Mas información en mi repo

Actualización:
Para estas fechas solo se necesita instalar

npm install @apollo/client graphql

el resto de dependencias del video no son necesarias. Luego en tu index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloProvider, InMemoryCache, ApolloClient } from '@apollo/client'
import { App } from './App'

const client = new ApolloClient({
  cache: new InMemoryCache(),
  uri: 'https://api-platzi-5vlnixk1i.vercel.app/graphql'
})

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

Todos los componentes se cargan de esa dependencia y en tu consumer, puedes usar esto:

import React from 'react'
import { PhotoCard } from '../PhotoCard'
import { gql, useQuery } from '@apollo/client'

const GET_PHOTOS = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`

export const ListOfPhotoCards = ({ categoryId }) => {
  const { loading, error, data } = useQuery(GET_PHOTOS, {
    variables: { categoryId }
  })

  if (loading) return <span>loading</span>
  if (error) return <p>Error</p>

  return (
    <ul>
      {
        data.photos.map(photoCard => <PhotoCard key={photoCard.id} {...photoCard} />)
      }
    </ul>
  )
}

ACTUALICEN ESTE CURSOOOOOOOOOOOOOOOO

Bueno, este es el pequeño aporte que puedo hacer, basándome en como estructuró el código un compañero en la clase anterior, para el que no haya implementado el componente padre como hizo el profesor, esta es mi solución, en el listOfPhotoCards, simplemente desestructuran ‘categoryId’ de los props y lo pasan como parámetro en 'variables: categoryId:'
Luego en el App.js ingresan el props con el numero y funciona perfecto.


import React from 'react'
import { PhotoCard } from '../PhotoCard'
import { useQuery } from '@apollo/react-hooks'
import { gql } from 'apollo-boost'

const getPhotos = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`

export const ListOfPhotoCards = ({ categoryId }) => {
  const { loading, error, data } = useQuery(getPhotos, { variables: { categoryId: categoryId } })
  if (loading) return <h2>Loading...</h2>
  if (error) return <h2>Error!</h2>
  return (
    <ul>
      {data.photos.map(photo => <PhotoCard key={photo.id} id={photo.id} src={photo.src} />)}
    </ul>
  )
}

El curso venía de maravilla, hasta que llegamos acá, y con las desactualizaciones, perdí al menos dos horas entre errores diferentes.

Es de suma importancia tener éstas cosas en cuenta sino la frustración intentando resolver las cosas es enorme.

Un MVC es un patrón de diseño de software que nos propone separar nuestro código de la siguiente manera:
M: modelo => withPhotos
V: vista => ListOfPhotoCardsComponent
C: controlador => ListOfPhotoCard

![](

El proyecto se encuentra desactualizado debido al cambio de la dependencia de apollo, tuve que resolverlo de la siguiente forma sin usar el hook y mantener la estructura lo más similar a como lo indica el profesor y usando el container:
App.js --llama al container y no al componente directamente

import React from 'react'
import { ListOfCategories } from './components/ListOfCategories'
import { GlobalStyle } from './styles/GlobalStyles'
import { ListOfPhotoCardsContainer } from './container/ListOfPhotoCardsContainer'
import { Logo } from './components/Logo'

export const App = () => (
  <>
    <GlobalStyle />
    <Logo />
    <ListOfCategories />
    <ListOfPhotoCardsContainer />
  </>
)

El contenedor tuve que renombrarlo por ListOfPhotoCardsContainer de otra forma genera problema al llamarse igual que componente, el cual, consume el hook para traer los datos y le pasa la data al componente por medio de una prop:

import React from 'react'
import { withPhotos } from '../hoc/withPhotos'
import { ListOfPhotoCards } from '../components/ListOfPhotoCards'
import { useQuery } from '@apollo/client'

export const ListOfPhotoCardsContainer = ({ categoryId }) => {
  const { loading, error, data } = useQuery(withPhotos, {
    variables: { categoryId }
  })

  if (error) {
    return <h2>Internal Server Error</h2>
  }
  if (loading) {
    return <h2>Loading...</h2>
  }

  return <ListOfPhotoCards data={data} />
}

El componente ListOfPhotoCards se modifico para que solo muestre la lista de fotos similar a como lo muestra el profesor:

// dependecies
import React from 'react'
// Components
import { PhotoCard } from '../PhotoCard'

export const ListOfPhotoCards = ({ data }) => {
  return (
    <ul>
      {data.photos.map((photo) => (
        <PhotoCard key={photo.id} {...photo} />
      ))}
    </ul>
  )
}

Trate de mantener la estructura y de momento me está trabajando bien

Implementando el hook de Apollo quedaría así:

const GET_PHOTOS = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`
 const { loading, error, data = { photos: [] } } = useQuery(GET_PHOTOS, {
    variables: { categoryId: categoryId }
  })

Todo esto esta demasiado desactualizado

Leyendo la documentacion de apollo resolvi tanto esta como la clase anterior Apollo

<code> 
const ANIMALS_QUERY = gql`
  query getPhotos($categoryId: ID){
    photos(categoryId: $categoryId){
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`

export const ListOfPhotoCard = ({ categoryId }) => {
  const { data, loading, error } = useQuery(ANIMALS_QUERY, {
    variables: { categoryId }
  })
  if (loading) return <Loading />
  if (error) return <pre>{error.message}</pre>
  return (
    <ul>
      {data.photos.map(photo => <PhotoCard key={photo.id} {...photo} />)}
    </ul>
  )
}

<code>


donde entra redux aqui la verdad no entiendo 😦

Hola, he utilizado el render props ApolloConsumer para disparar una query en una accion(por ejemplo un click) y funciona sin problemas,sin embargo como se implemetaria esto en una la forma de HOC?

Mi solucion usando hooks 👉Click 😉

Para los que usan hooks https://www.apollographql.com/docs/react/api/react/hooks/#usequery

import React from 'react'
import { gql, useQuery } from '@apollo/client'
import { PhotoCard } from '../PhotoCard'
import { List, Item } from './style.js'

const GET_PHOTOS = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`

export const ListOfPhotoCard = () => {
  const { loading, error, data } = useQuery(GET_PHOTOS, {
    variables: { categoryId: 1 } //TODO: Enviar dinamicamente
  })

  if (loading) {
    return <h1>Loading</h1>
  }

  if (error) {
    return <h1>{error.message}</h1>
  }
  return (
    <>
      <List>
        {data.photos.map((photoCard) => (
          <Item key={photoCard.id}>
            <PhotoCard {...photoCard} />
          </Item>
        ))}
      </List>
    </>
  )
}

Excelente. Gracias!!

Una forma ordenada de trabajar es separar el apollo de nuestro archivo Index de la siguiente manera (espero les sirva)

import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloComponent } from './apollo';
import { App } from './App';



ReactDOM.render(
<ApolloComponent>
  <App />
</ApolloComponent>,
 document.getElementById('app'));

import React from 'react';
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'

const client = new ApolloClient({
  uri: "https://petgram-server-max-seven.vercel.app/graphql",
  cache: new InMemoryCache(),
});

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

Una aclaracion:
A dia de hoy la metodologia para hacer esta clase es diferente, y lo mas probable es que no hayas utilizado la funcion graphql() para el query withPhotos.
De ser asi, esta funcion NO SE CONSIDERA UN HOC.
Por definicion, un HOC es una funcion que recibe como parametro un componente y retorna otro componente.

You are still able to use either HOCs or render props in Apollo client, but both ways are now obsolete and replaced with official React Hooks. You can also check out this article on pros and cons of higher-order components, render props, and React Hooks (…)

From: https://atheros.ai/blog/react-hooks-in-apollo-client-for-graphql-queries-and-mutations

preparar el servidor tambien es una tarea de un frontend o eso ya depende de backend? en dado caso que sea otra tarea neustra que cursos me recomiendan tomar para aprender esa parte.

Este cuate se complica demasiado jajaja

Pero si tenemos diferentes puntos de acceso graphql ¿? como debemos utilizarlos si ahora en el index.js ya pones que el ApolloProvider tiene un client como hacer con varios¿?

Hola Devs:
-Aqui les traigo un poco de documentacion:HOC

Variables con apollo client en un query con TypeScript actualmente 2023

  • hacemos la consulta

    import { gql } from '@apollo/client'
    export const getPhotos = gql`
        query ($id:ID!){
      		photos(categoryId:$id) {
       				id
       				likes
        			src 
        			liked
      		 }
    	 }
    `
    //$id variable
    

luego utilizamos el hook useQuery y recibe un segundo argumento que son las opciones, en esas opciones
tenemos un objeto que recibe las variables

import { PhotoCard, PropsPhotoCard } from "../PhotoCard";
import { getPhotos } from "../../graphql/querys/photos";
import {useQuery} from '@apollo/client'

export const ListOfPhotoCards =()=>{
		//feching de datos con el hook useQuery
    const {data,loading} = useQuery<{photos:PropsPhotoCard[]}>(getPhotos,{
        variables:{ // var of query
            id:"1"
        }
    });

    //console.log(data)
    const photos = data?.photos
    return(
        <ul>
            { loading && <li>Loading...</li>}
            {  photos?.map(photo=>(
            <PhotoCard {...photo} />
            ))}
        </ul>
       
    )

}

En vista de las actualizaciones de graphql a uso de hooks, tome la decision de crear un HOC para extender la funcionalidad de mi componente hijo y separandolo del padre quien se encarga de la conexion con graphql:

  1. GraphqlContainer.jsx
import React from 'react'
import { useQuery} from "@apollo/client";

export function GraphqlContainer(WrappedComponent, query, variables) {
    return function GraphqlContainerWithQuery() {

        const useQueryResult = useQuery(query, {
            variables: { ...variables },
        });
        
        return (
            <>
                <WrappedComponent {...useQueryResult} />
            </>
        );
    };
}

  1. ListOfProductCards.jsx
import React from "react";
import PhotoCard from "../PhotoCard/PhotoCard";
import { GraphqlContainer } from "../../containers/graphqlContainer";

import { gql } from "@apollo/client";

const withPhotos = gql`
    query getPhotos($categoryId: ID) {
        photos(categoryId: $categoryId) {
            id
            categoryId
            src
            likes
            userId
            liked
        }
    }
`;

function ListOfPhotoCardComponent({data, loading, error}) {

    if (loading) return "Loading...";

    if (error) return <pre>{error.message}</pre>;

    return (
        <>
            {data.photos.map((photo) => (
                <PhotoCard key={photo.id} {...photo} />
            ))}
        </>
    );
}

const ListOfPhotoCard = GraphqlContainer(ListOfPhotoCardComponent, withPhotos, { categoryId: 2})

export { ListOfPhotoCard };


emulando un poco como se hacia antes de graphql

Actualización a React 18 (Julio 2022)
Cambia la manera de iniciar la aplicación, utilizando ReactDOM.createRoot en vez del viejo ReactDOM.render.
El src/index.js quedará asi:

// src/index.js

import React from 'react'
import ReactDOM from 'react-dom/client'
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'

import { App } from './App'

const client = new ApolloClient({
  uri: 'https://direccion-API-de.vercel.app/graphql',
  cache: new InMemoryCache()
})

// React 18 new way to mount the app...
const container = document.getElementById('app')
const root = ReactDOM.createRoot(container)
root.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>
)

Infortunadamente muchas de las cosas que dice el instructor acá, no se pueden realizar cuando se emplea typescript debido a la cantidad de types que se deben definir. El graphql en sus nuevas versiones no se puede definir fuera de una función de react component.

Les dejo la forma en que lo deja sin embargo dista mucho de lo que se explico en esta clase

Componente ListOfPhotoCards

import React, { FC } from "react";
import { PhotoCard } from "../PhotoCard";
import { Lista, Item } from "./styles";
import { useQuery } from "@apollo/client";
import { GET_PHOTOS } from "../hoc/withPhotos";

interface photos {
  photos: {
    id: string;
    categoryId: string;
    src: string;
    likes: number;
    userId: string;
    liked: string;
  }[];
}

type Props = {
  categoryId: number;
};

interface photosVars {
  categoryId: number;
}

export const ListPhotoCards: FC<Props> = ({ categoryId }) => {
  const { loading, error, data } = useQuery<photos, photosVars>(GET_PHOTOS, { variables: { categoryId } });
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :</p>;

  const photos = data?.photos;
  return (
    <Lista>
      {photos && photos.map((photo) => (
        <Item key={photo.id}>
          <PhotoCard {...photo} />
        </Item>
      ))}
    </Lista>
  );
};

componente hoc

import { gql } from "@apollo/client"

export const GET_PHOTOS = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`;

Los componentes de orden superior son una técnica utilizada en React que nos permite reutilizar la lógica de los componentes. Más específicamente, un componente de orden superior es una función que toma un componente como argumento y devuelve un componente.

En mi caso no pude agregar la carpeta de container ya que no sé como, me gustaría que el curso estuviera actualizado… Solo pude llegar a seprar el hoc.


Me mareé un poco con tanto cambio de posición en los componentes…

Los containers definen de manera más ordenada la arquitectura, me agrada la separación de lógicas

Este curso es Genial, gracias Platzi, Gracias Midudev…!!

container: es el que se encarga de hacer el fetching de datos de nuestro componente

Para los que trabajamos con Hooks, supongo que seguimos con MV debido a que no usamos un HOC

v