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

Usar render Props para recuperar una foto

23/50
Recursos

Aportes 60

Preguntas 11

Ordenar por:

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

A mi me botaba error y me tocó inicializar la variable data y la variable photo y dejarlas vacias.

<Query query={query} variables={{ id }}>
            {
                ({ loading, error, data = { photo: {} } }) => {
                    const { photo = {} } = data;
                    return (< PhotoCard {...photo} ></PhotoCard>)
                }
            }
        </Query >

Si les pasa que al hacer clic en el detalle en una foto para ver su detalle, se rompe y dice que data no está definido en consola, prueben cambiar el PhotoCardWithQuery asi:

export const PhotoCardWithQuery = ({ id }) => (
  <Query query={query} variables={{ id }}>
    {
      ({ loading, error, data }) => {
        if (loading) return null
        const { photo = {} } = data
        return <PhotoCard {...photo} />
      }
    }
  </Query>
)

Render props

.
Me costó un poco entender lo de las render props, pero después de investigación externa, es relativamente fácil de entender.
.
La técnica de render props está basada en la propiedad children de los componentes de react, envés de renderizar un componente hijo en el componente padre, renderizas una función que devuelve un componente, a la función le pasas como parámetros los objetos que desees (puede ser un fetching de base de datos como lo vimos en esta clase) y puedes acceder a la información como si ya la tuvieras a la hora de montar el componente padre con un hijo de una función.

Un ejemplo

.
Primero creamos un componente que haga toda la lógica del fetching de datos y regrese una función:
.

const GetPokemon = ({ children, pokemonNumber }) => {
  const [pokemon, setPokemon] = useState([]);
  useEffect(() => {
    window.fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonNumber}/`)
      .then((res) => res.json())
      .then((myPokemon) => {
        setPokemon({
          src: myPokemon.sprites.front_default,
          name: myPokemon.species.name,
          id: myPokemon.id,
        });
      })
      .catch((error) => { console.error(error); });
  }, []);
  return ( // acá toda hacer un return del children como función
    <div>
      {children(
        { pokemon }, // en los argumentos dejamos la información que queramos que sea accesible para otros componentes
      )}
    </div>
  );
};

.
Después ya podemos acceder a la data del componente al invocarlo y pasar en el children una función con el mismo argumento que fue declarada:
.

<GetPokemon
  pokemonNumber={key + 1}
  key={key + 1}
>
  {
    ({ pokemon = {} }) => (
      <Pokemon
        src={pokemon.src}
        pokemonName={pokemon.name}
        pokemonNumber={pokemon.id}
        key={key + 1}
      />
    )
  }
</GetPokemon>

.
Dejo acá el repositorio en el que con 3 componentes básicos (App.jsx, Pokemon.jsx y GetPokemon.jsx) juego con las render props

Para los que utilizan Hooks

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

const query = gql`
  query getSinglePhoto($id: ID!) {
    photo(id: $id) {
      id
      categoryId
      src
      likes
      liked
      userId
    }
  }
`

export const PhotoCardWithQuery = ({ id }) => {
  console.log(id)
  const { loading, error, data } = useQuery(query, {
    variables: {
      id: id
    }
  })
  if (error) {
    return <h2>Internal Server Error</h2>
  }
  if (loading) {
    return <h2>Loading...</h2>
  }

  return (
    <PhotoCard {...data.photo} />
  )
}

esta que saca chispa el boton del pause! y eso que lo puse en 0.85x jaja

Chicos, al dia de hoy hice la siguiente aplicacion para poder usar render props,
![](

El reto de pasar el hoc a render Props lo hice así:

  • En la carpeta container creé un archivo que se llama ListOfPhotoCardsWithQuery.js
import React from 'react'
import { PhotoCard } from '../components/PhotoCard'

import { gql } from 'apollo-boost'
import { Query } from 'react-apollo'

const query = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      liked
      userId
    }
  }
`
export const ListOfPhotoCardsWithQuery = ({ categoryId }) => (
  <Query query={query} variables={{ categoryId }}>
    {
      ({ loading, error, data }) => {
        const { photos = [] } = data
        return (
          <ul>
            {photos.map(photo => <PhotoCard key={photo.id} {...photo} />)}
          </ul>
        )
      }
    }
  </Query>
  • Y el archivo App.js quedaría así
export const App = () => {
  const urlParams = new window.URLSearchParams(window.location.search)
  const detailId = urlParams.get('detail')

  return (
    <div>
      <GlobalStyle />
      <Logo />
      {
        detailId
          ? <PhotoCardWithQuery id={detailId} />
          : <Fragment>
            <ListOfCategories />
            <ListOfPhotoCardsWithQuery categoryId={1} />
          </Fragment>
      }
    </div>
  )
}

si sustituiste las dependencias apollo-boost y react-apollo por @apollo/client

para importar Query seria de la siguiente manera:

import { Query } from '@apollo/client/react/components';

y agrega un valor por defecto en caso te lance el error de photo undefinded

const { photo } = data || { photo: {} };

para continuar con el curso.

Quería compartir con ustedes este custom hook para hacer el query del video:

useGetSinglePhoto.js

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

export const useGetSinglePhoto = (id) => {
  const getSinglePhoto = gql`
    query getSinglePhoto($id:ID!) {
      photo(id:$id) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
  `

  const { loading, error, data } = useQuery(getSinglePhoto, {variables: { id }})

  return { loading, error, data }
}

PhotoCardWithQuery.js

import { PhotoCard } from '../PhotoCard'
import { useGetSinglePhoto } from '../../hooks/useGetSinglePhoto'

export const PhotoCardWithQuery = ({ id }) => {
  const { loading, data } = useGetSinglePhoto(id)

  if (loading) return null

  const { photo = {} } = data

  return <PhotoCard {...photo} />
}

Si quieren saber más sobre render props: https://es.reactjs.org/docs/render-props.html

Tengan en cuenta tambien que el proyecto react-apollo esta deprecado https://github.com/apollographql/react-apollo

warning THIS PROJECT HAS BEEN DEPRECATED warning

Please note that 4.0.0 is the final version of all React Apollo packages. React Apollo functionality is now directly available from @apollo/client >= 3. While using the @apollo/react-X packages will still work, we recommend using the following imports from @apollo/client directly instead:

Un articulo buenisimo que els ayudará a entender mejor esto
https://medium.com/simply/comparison-hocs-vs-render-props-vs-hooks-55f9ffcd5dc6

Con Hooks year 22

Container

import React from 'react'
import { PhotoCard } from '../components/PhotoCard'
import { useGetPhotoWithQuery } from '../hooks/useGetPhotoWithQuery'

export const PhotoCardWithQuery = ({ id }) => {
  const { loading, error, data } = useGetPhotoWithQuery(id)

  if (loading) return <div>Loading</div>
  if (error) return <div>error</div>

  return (
    <>
      <a href='/'>BACK</a>
      <PhotoCard {...data.photo} />
    </>
  )
}

Hook

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

export const useGetPhotoWithQuery = id => {
  const GET_PHOTO = gql`
    query getSinglePhoto($id: ID!) {
      photo(id: $id) {
        id
        categoryId
        src
        likes
        userId
        liked
      }
    }
  `

  const { loading, error, data } = useQuery(GET_PHOTO, {
    variables: { id }
  })

  return { loading, error, data }
}

Y la misma logica del profe

High order components, render props, y ahora hooks!

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

const getSinglePhoto = gql`
  query getSinglePhoto($id: ID!) {
    photo(id: $id) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`

export const useGetSinglePhoto = id => {
  const { loading, data, error } = useQuery(getSinglePhoto, { variables: { id } })
  return { loading, data, error }
}

Con hooks parece más fácil todo…

me toco hacerlo de la siguiente manera porque ya no sirve la libreria react-apollo

import React, { Fragment } from 'react';
import { PhotoCard } from '../components/PhotoCard';

import { gql } from 'apollo-boost'
//import { Query } from '@apollo/client/react/components'
import { useQuery } from '@apollo/react-hooks'

const query = gql`
    query getSinglePhoto($id:ID!) {
        photo(id:$id) {
            id
            categoryId
            src
            likes
            userId
            liked
        }
    }
`

const renderizarPhoto = (data) => {

    if(data){
        console.log(data)
        return (
            <Fragment>
                 <PhotoCard {...data.photo} />
            </Fragment>
        )
    }else{
        return (
            <h1>No he cargado</h1>
        )
    }
}

export const PhotoCardWithQuery = ( {id }) => {
  const { loading, error, data } = useQuery(query, { variables: { id } });
    
   return(
        <Fragment>
            {renderizarPhoto(data)}
        </Fragment>
   )
}

Para los que deseen hacerlo con react-hook de apollo:

PhotoCardWithQuery.js

import React from 'react'
import { PhotoCard } from '../components/photo_card/'
import { obtenerUnicaFoto } from '../hoc/obtenerUnicaFoto'

import {useQuery} from '@apollo/react-hooks'

export const PhotoCardWithQuery = ({ id }) => {
    const {loading, error, data}=useQuery(obtenerUnicaFoto,{
        variables:{
            id
        }
    })

    if(loading) return null

    const { photo = {} } = data

    return(
        <PhotoCard {...photo} />
    )

}

Aqui toca iniciar el _photo _que viene del _data _con un objeto vacio, sino arroja un error. Tambien se valida con el _loading _para no traer nada mientras carga (tal como se mencionan en otros comentarios)

Cree un hoc llamado obtenerUnicaFoto.js (usado arriba) para separar la consulta al Graphql como se hizo en las categorias

obtenerUnicaFoto.js

import {gql} from 'apollo-boost'

export const obtenerUnicaFoto = gql`
query obtenerFoto($id:ID!){
  photo(id:$id){
      id
      categoryId
      src
      userId
      likes
  }
}
`

Y finalmente en el App.js hice lo mismo que hace el profesor, sin embargo le modifique un poco para que mantuviera las categorias en la parte de arriba:

App.js

export const App = () => {
    const paramsURL = new window.URLSearchParams(window.location.search)
    const detailId = paramsURL.get('detail')
    // console.log(detailId)

    return (
        <div>
            <GlobalStyles />
            <Logo />
            <ListaCategoria />
            {
                detailId
                    ? <PhotoCardWithQuery id={detailId} />
                    :<ListaPhotoCard categoryId={2} />
            }
        </div>
    )
}

Hola!

Siguiendo los pasos, a la hora de ver el contenido de data en el console.log no me muestra el objeto vacío, sino undefined.

Al intentar recuperar la photo de data y pasarla al componente me da el error Uncaught TypeError: Cannot read property ‘photo’ of undefined

¿A que se podría deber si ya le estamos dando un valor por defecto?

Adjunto el código de PhotoCardWithQuery.js

import React from 'react'
import { PhotoCard } from '../components/PhotoCard'

import { gql } from 'apollo-boost'
import { Query } from 'react-apollo'

const query = gql`
query getSinglePhoto($id:ID!) {
  photo(id:$id) {
    id
    categoryId
    src
    likes
    userId
    liked
  }
}
`

export const PhotoCardWithQuery = ({ id }) => (
  <Query query={query} variables={{ id }}>
    {
      ({ loading, error, data }) => {
        const { photo = {} } = data
        return <PhotoCard {...photo} />
      }
    }
  </Query>
)

Un saludo

(4 de Marzo 2021)
Quizas pude dar con la solucion de tu problema
No me hes muy claro, pero en sí, el proyecto de react apollo está deprecated . Lo cual si hay bugs o problemas, no habrá soporte para ello.
Si tu seguiste los comentarios de las clases pasadas, entonces instalaste @apollo/react-hooks. Si es asi, te cuento que tu error es el mismo que el mio. Por ende, debes de no usar esa dependencia sino usar la que usaba el profesor "react-apollo"
Con base en esto, ahora debes hacer todo tal y cual como lo elaboró el profesor en las clases pasadas (de este mismo modulo claro)
Lo cual no es mucho, pues si te fijas solo es la configuración del archivo index, los hocs, los containers y uno que otro archivo.
Me tomó solo 20 mins hacerlo, claro está, con la ayuda del repo en github del profesor Link del repo de esta clase
Pd: No olvides seguir usando la uri de tu proyecto de vercel
Espero haber solucionar tu problema, si es el mismo que el mio.
Exitos

¿Alguien me puede ayudar con este error, por favor?

Recuerden poner las variables en Query Variables no en HttpHeaders por error.

Podemos usar Fragment sin necesidad de importarlo ni escribir <Fragment>, simplemente con <> y </> para cerrar estaremos usando Fragments

Hola, tengo este error…

PhotoCardWithQuery.js:36 Uncaught TypeError: Cannot read property ‘photo’ of undefined

Pero tengo todo el codigo exacto, alguien podria ayudarme ?

Reto

hoc => hooks

import { useQuery } from '@apollo/react-hooks';
// eslint-disable-next-line import/no-extraneous-dependencies
import gql from 'graphql-tag';

const getPhotos = gql`
  query getPhotos($categoryId: ID) {
    photos(categoryId: $categoryId) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`;
const useGetPhotos = (categoryId) => {
  const { loading, data, error } = useQuery(getPhotos, { variables: { categoryId } });
  return { loading, data, error };
};

export default useGetPhotos;

para la query:

query getSinglePhoto($id:ID!) {
  photo(id:$id) {
    id
    categoryId
    src
    likes
    userId
    liked
  }
}

tengo el siguiente error:

{
  "error": {
    "errors": [
      {
        "message": "Variable \"$id\" of required type \"ID!\" was not provided.",
        "locations": [
          {
            "line": 1,
            "column": 22
          }
        ],
        "extensions": {
          "code": "INTERNAL_SERVER_ERROR"
        }
      }
    ]
  }
}

esto directo desde el graphql, 😕 , está mal mi backend?

PhotoCardWithQuery.js

import React from 'react';
import { PhotoCard } from '../Components/PhotoCard'
import { useGetSinglePhoto } from '../Hooks/useGetPhoto'

export const PhotoCardWithQuery = ({ id }) => {
  const { loading, data, error } = useGetSinglePhoto(id)

  if (loading) return null
  if (error) return <h1>Error</h1>

  const { photo = {} } = data

  return <PhotoCard {...photo} />
}

Hooks/useGetPhoto.js

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

export const useGetSinglePhoto = (id) => {
    const getSinglePhoto = gql`
      query getSinglePhoto($id:ID!) {
        photo(id:$id) {
        id
        categoryId
        src
        likes
        userId
        liked
      }
    }
`

const { loading, error, data } = useQuery(getSinglePhoto, {variables: { id }})

  return { loading, error, data }
}

App.js

import React from "react";

//styles
import { GlobalStyle } from "./Styles/GlobalStyles";

import { ListOfCategories } from './Components/ListOfCategories';
import { ListOfPhotoCards } from './Components/ListOfPhotoCards';
import { Logo } from './Components/Logo';

import {PhotoCardWithQuery} from './Container/PhotoCardWithQuery'

export const App = () =>{
    const  urlParams = new window.URLSearchParams(window.location.search)
    const detailId = urlParams.get('detail')
    // console.log(detailId)
    return (
        <>
            <GlobalStyle />
            <Logo />
            {
                detailId
                ?
                    <PhotoCardWithQuery id={detailId} />
                :
                <> 
                    <ListOfCategories />
                    <ListOfPhotoCards categoryId={1}/>
                </>
            }
        </>

    )
} 

Copy paste de Apollo (:

# Get photo by ID
query getSinglePhoto($id:ID!) {
  photo(id:$id) {
    id
    categoryId
    src
    likes
    userId
    liked
  }
}

en vez de <Fragment> </Fragment> se puede usar <> </>

Puedes usar <Fragment> sin necesidad de exportar de la siguiente manera:

return(
    <>
        <h1>My Fragment</h1>
    </>
)

Mi solucion con HOOKS
…/containers/PhotoCardWithQuery.js

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

function getSinglePhoto(id) {
    const getSinglePhoto = gql`
    query getSinglePhoto($id: ID!){
        photo(id:$id){
            id
            categoryId
            src
            likes
            userId
            liked
        }
    }
    `
    return useQuery(getSinglePhoto, {variables: {id}})
}

export const PhotoCardWithQuery = ({id}) => {
    const {loading, error, data} = getSinglePhoto(id)
    if(loading) return 'Cargando...'
    return (<PhotoCard {...data.photo}/>)    
}```

ouch! de la manera que estaba siguiendo esta deprecado el component Query 😦

https://www.apollographql.com/docs/react/api/react/components/

NOTE: React Apollo’s render prop components are deprecated. They will continue to receive bug fixes until March 2020, after which they will no longer be maintained by Apollo.

Si aún siguen este curso (que me parece desde 0 que está buenísimo y @midudev es un instructor enorme!) y tienen un error al implementar PhotoCardWithQuery, aquí les dejo una validación que podría ser útil y más legible que validar con un if:

export const PhotoCardWithQuery = ({ id }) => {
  return (
    <Query query={query} variables={{ id }}>
      {
        ({ loading, error, data }) => {
          const { photo = {} } = !!data && data //⬅
          console.log(data)
          return <PhotoCard />
        }
      }
    </Query>
  )
}

En complejidad, veo que no hay mucha diferencia entre HOC y Render Props, salvo que en el segundo nos ahorramos la carpera HOC. Incluso veo que la lógica de recibir un componente para transformarlo se mantiene aunque de forma distinta. ¿Hay alguna diferencia en cuanto a rendimiento u otra que sea relevante?
Gracias
Slds.

Mi high order component convertido a render props:

import React from 'react';

import { ListOfPhotocards } from '../components/ListOfPhotocards';

import { gql } from 'apollo-boost';
import { Query } from 'react-apollo';

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

export const ListOfPhotocardsWithQuery = ( { categoryId } ) => (
    <Query query={query} variables={ { categoryId } }>
        {
            ({loading, error, data}) => {
                if(loading) {
                    return <h1>Cargando...</h1>
                } else {
                    const { photos } = data;
                    return <ListOfPhotocards photos={photos} />
                }
            }
        }
    </Query>
)

Les comparto mi código hecho con useQuery (me parece mejor)

import React from 'react';
import { PhotoCard } from "../react-components/PhotoCard";

/* GraphQL and Apollo */
import { gql } from "apollo-boost";
import { useQuery } from 'react-apollo';


const query = gql`
   query getSinglePhoto ($id: ID!){
      photo (id: $id){
         id
         categoryId
         src
         likes
         userId
         liked
      }
   }
`

export const PhotoCardDetails = (props: any) => {
   const { id } = props;
   const { data, loading } = useQuery(query, {variables: {id}})
   
   return (
      <>
      {loading 
         ? <PhotoCard />
         : <PhotoCard details={data.photo}/>
      }
      </>
   )
}

Hola Coders,

Intente hacer el ejercicio con Hooks y este fue mi resultado.

hooks/useGetPhoto.js

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

export function useGetPhoto(id) {
const getPhotoById = gql`
 query getSinglePhoto($id:ID!) {
  photo(id:$id) {
      id
      categoryId
      src
      likes
      userId
      liked
  }
 }
`;

 const { data, loading, error } = useQuery(getPhotoById, {
  variables: {
   id
  }
 });

 return { data, loading, error };
}

components/PhotoCardDetails.js

import React from 'react';
import { PhotoCard } from '../PhotoCard';
import { useGetPhoto } from '../../hooks/useGetPhoto';

export const PhotoCardDetails = ( { id } ) => {
    const {data, loading, error} = useGetPhoto(id);
    if(loading) return "Cargando...";
    return(
        <PhotoCard {...data.photo}/>
    );
}

Me gustaría obtener feed de que piensan de este código y de como se puede mejorar.

Saludos!

AndresIOI

Una validacion por si marca photo como ‘undefined’ y de paso aprovechando para colar un <Loading />

export const PhotoCardWithQuery = ({id}) => (
  <Query query={query} variables={{ id }}>
      {
          ({ loading, error, data }) => {
            if (!data) {
              return <Loading />
            } else {
              const { photo = {} } = data;
              return (< PhotoCard {...photo} ></PhotoCard>)
            }
              
          }
      }
  </Query >
)


Buen dia quien me puede ayudar con este error , no quiere retornarme los datos de la consulta, si pruebo directamente en graphql observo que me genera el mismo error y creo que es debido a que el id esta tipo string. Como puedo hacer para que me compare con tipo string?

Si les da que photo es undefined, coloquen esto

({ loading, error, data }) => {
  if(loading) {
    return <PhotoCard {...data} /> 
  }
   const { photo = {} } = data
   return <PhotoCard {...photo} /> 
  	  	  
}

Esto sucede ya que efectivamente photo no existe al comienzo de la llamada, asiendo esto retornamos la card con la imagen por defecto(aquí podrías crear una card de carga) y retornara la card especifica una vez que el loader termine y la data este.
Nunca pares de aprender

Mi resultado de usar el container, hoc y component:
En el hoc:
import React from 'react’
import { gql } from '@apollo/client’
import { Photocard } from ‘…/components/PhotoCard’

const GET_SINGLE_PHOTO = gqlquery GET_SINGLE_PHOTO($id: ID!){ photo(id:$id){ id categoryId src likes userId liked } }
const renderProp = ({ loading, error, data }) => {
if (loading) return 'Loading…'
if (error) return 'An error ocured in the server’
else {
const { photo = {} } = data
return <Photocard {…photo} />
}
}
export {
GET_SINGLE_PHOTO,
renderProp
}

En el PhotoCardWithQuery
import React from 'react’
import { Query } from '@apollo/client/react/components’
import { GET_SINGLE_PHOTO, renderProp } from ‘…/hoc/renderProp’

export const PhotoCardWithQuery = ({ id }) =>
(
<Query query={GET_SINGLE_PHOTO} variables={{ id }}>
{renderProp}
</Query>
)

ES++ puedes usar ? para que la propiedad de un objeto lo tome como opcional

const { loading, data } = useQuery(GET_PHOTO_DETAILS, { variables: { id: detailId }, });
const photo = data?.photo

query getSinglePhoto

En Nexts, solo debí crear en la carpeta ‘pages’ una carpeta con el nombre ‘detail’ y adentro un archivo con el nombre [id].js, al cual le agregué este código:

<code>
import React from 'react';
import { useRouter } from 'next/router';
import PhotoCard from '@components/PhotoCard/PhotoCard';
import { useQuery } from '@apollo/react-hooks';
import { gql } from 'apollo-boost';
const query = gql`
  query getSinglePhoto($id: ID!) {
    photo(id: $id) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`;

const PhotoDetail = () => {
  const {
    query: { id },
  } = useRouter();
  const { loading, error, data } = useQuery(query, { variables: { id } });

  if (loading) return 'Loading...';
  return <PhotoCard {...data.photo} />;
};

export default PhotoDetail;

El repositorio con el avance hasta este momento:

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

Para este momento de la clase los renders-props no me funcionaron como esperaba, intenté varias cosas hasta que elegí la perspectiva de los hooks… al final fue mas corto y no rompe el ejemplo de @midudev.

import React from 'react'
import { useQuery } from '@apollo/react-hooks'

import { getSinglePhoto } from '../hocs/getSinglePhoto'

import { PhotoCard } from '../components'

export const PhotoCardWithQuery = ({id}) => {
  const { loading, error, data: {photo = []} = {} } = useQuery(getSinglePhoto, { variables: { id } })
  
  if (loading) return <p>Loading...</p>
  if (error) return <p>Error! ⛔: {error.message}</p>
  return <PhotoCard {...photo} />
}

Clase tan compleja, pero llena de aprendizaje, un par de trabas con graphql y el paso de las fotos, pero valió cada maldito segundo :’)

con el ejercicio del profesor me arrojo demasiados errrores y para continuar use los hooks de apollo.
aún no investigo afondo el concepto de render props y se me es algo confuso y no sé si mi siguiente codigo cumpla con esta técnica


const PhotoCardWithQuery = ({ id }) => {
  const { loading, error, data } = useQuery(GET_PHOTO, { variables: { id } })
  if (loading) return 'Loading...'
  if (error) return `Error! ${error.message}`
  const { photo } = data

  return (<Photocard {...photo} />)
}
export default PhotoCardWithQuery

Hola Devs:
-Me costo un poquito entender como funcionan los Render Props, pero despues de leer un poco y hacer prueba y error (se los recomiendo para entender un problema), pude obtener mi solucion y al mismo tiempo entender como funciona:
Aqui esta el commit del codigo de esta clase en mi repo por si necesitan el codigo: Click Aqui

Buenos dias una pregunta que es mejor utilizar para recuperar datos, utilizar componente de orden superior (hoc) o render props?

Anda fallando el servido de graphql!

Screen Shot 2020-01-17 at 21.00.43.png

¿Por que hacemos la carpeta container?

Hola, tengo un monton de advertencias de los devtools… a qué creen que se deberá?
![](

Agregando loading para evitar error con objeto photo en undefined

import React, { Fragment } from 'react'
import { PhotoCard } from '../components/PhotoCard'
import { gql } from 'apollo-boost'
import { Query } from 'react-apollo'
import Skeleton from 'react-loading-skeleton'
const query = gql`
    query getSinglePhoto($id:ID!) {
        photo(id:$id) {
            id
            categoryId
            src
            likes
            userId
            liked
        }
    }
`

const renderLoading = () => {
  return <Fragment>
    <Skeleton height={75} />
    <Skeleton height={32} width={50} />
  </Fragment>
}
export const PhotoCardWithQuery = ({ id }) => (
  <Query query={query} variables={{ id }}>
    {
      ({ loading, error, data = { photo: {} } }) => {
        const { photo = {} } = data
        return loading ? renderLoading() : <PhotoCard {...photo} />
      }
    }
  </Query>
)
export const PhotoCardWithQuery = ({ id }) => (
  <Query query={query} variables={{ id }}>
    {
      ({ loading, error, data }) => {
        if (loading) return null

        const { photo = {} } = data
        return <PhotoCard {...photo} />
      }
    }
  </Query>
)

A mi me daba error y tuve que hacer algo con la variable loading. A Alguien mas le paso? alguien sabe poerque puede ser eso? Dejo fragmento del codigo

export const PhotoCardWithQuery = ({ id }) => (
  <Query query={query} variables={{ id }}>
    {
      ({ loading, error, data }) => {
        if (loading) return 'cargando...'
        const { photo = {} } = data
        return <PhotoCard {...photo} />
      }
    }
  </Query>
)```

Mi solución =P

import React from 'react'
import { ListOfPhotoCardComponent } from '../components/listOfPhotoCard'

import { gql } from 'apollo-boost'
import { Query } from 'react-apollo'

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

export const ListOfPhotoCardsWithQuery = ({ categoryid }) => (
  <Query query={query} variables={{ categoryid }}>
    {
      ({ loading, error, data }) => {
        if (loading) return null
        return <ListOfPhotoCardComponent data={data} />
      }
    }
  </Query>
)

(…) 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

aquí está mi reto, Agregue esto y le quite graphql a withPhotos para poderlo pasar a query 💪🏼

import React from 'react'
import { Query } from 'react-apollo'

import { withPhotos } from '../hoc/withPhotos'
import { ListOfPhotoCardComponent } from '../components/ListOfPhotoCard/index'

export const ListOfPhotoCards = ({ id }) => {

  return (
    <Query query={withPhotos} variables={{id}}>
      {
        ({data = {}}) => {
          return <ListOfPhotoCardComponent {...data}/>
        }
      }
    </Query>
  )
}

Dejo aca mi solucion utilizan apollo/react-hooks

photoCardWithQuery

import { gql } from "apollo-boost";
import { useQuery } from "@apollo/react-hooks";

const query = gql`
  query getSinglePhoto($id: ID!) {
    photo(id: $id) {
      id
      categoryId
      src
      likes
      userId
      liked
    }
  }
`;

export const PhotoCardWithQuery = ({ detailId }) => {
  const { loading, error, data = {} } = useQuery(query, {
    variables: { id: detailId },
  });
  if (loading) return <p>Cargando...</p>;
  if (error) return <p>Se dano</p>;
  console.log(data);

  return <PhotoCard {...data.photo} />;
};

App.js

import React from "react";
import ListOfCategories from "./components/ListOfCategories";
import { GlobalStyle } from "./styles/GlobalStyles";
import ListOfPhotoCards from "./components/ListOfPhotoCards";
import Logo from "./components/Logo";
import { PhotoCardWithQuery } from "./components/container/photoCardWithQuery";

const App = () => {
  //Consiguiendo el id en la barra de nav
  const urlParams = new window.URLSearchParams(window.location.search);
  const detailId = urlParams.get("detail");
  //console.log(detailId);

  return (
    <div>
      <GlobalStyle />
      <Logo />
      {detailId ? (
        <PhotoCardWithQuery detailId={detailId} />
      ) : (
        <>
          <ListOfCategories />
          <ListOfPhotoCards detailId={detailId} />
        </>
      )}
    </div>
  );
};

export default App;

Vengo de PHP y estas líneas

const urlParams = new window.URLSearchParams(window.location.search)
const detailId = urlParams.get('detail')

Me suenan muchísimo a

$_GET["detail"]

Disculpen mi ignorancia pero ¿Hay alguna forma de limpiar estos parámetros para evitar una posible inyección de código?

Saludos y gracias

Interesante. 😃 gracias!!

Hola! Alguien me puede explicar como se suben imagenes en este chat?