No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Consumiendo la FakeStore API para pintar cards

8/31
Recursos

Aportes 61

Preguntas 7

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

La API de Platzi no es estable y eso puede traerte resultados inesperados como im谩genes sin relaci贸n al producto, poco o demasiados datos, etc. Yo les aconsejo usar la API de Fake Store. Es muy similar.
Para las im谩genes, eliminen 煤nicamente la posici贸n ([0]). En cuanto al t铆tulo de los productos, si les causa ruido que sean muy extensos, pueden agregar la propiedad truncate de Tailwind para agregar elipsis. Tambi茅n puedes agregar un mr-2 (margin-right) y quedar谩 excelente.

Seamos un poco m谩s profesionales 馃槈

Creemos un archivo donde vivir谩 la url de la api en .src/api/index.js:

export const apiUrl = 'https://api.escuelajs.co/api/v1'

Usemos async y await y SIEMPRE usemos try catch en peticiones GET:

import { useState, useEffect } from "react"
import { Layout } from "../../Components/Layout"
import { Card } from "../../Components/Card"

import { apiUrl } from '../../api/'

export const Home = () => {
  const [Items, setItems] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(`${apiUrl}/products`)
        const data = await response.json()
        setItems(data)
      } catch (error) {
        console.error(`Oh no, ocurri贸 un error: ${error}`);
      }
    }
    fetchData()
  }, [])


  return (
    <Layout>
      Home
      <section className="grid gap-4 grid-cols-4 w-full max-w-screen-lg">
        {
          Items?.map(item => (
            <Card
              key={item.id}
              data={item}
            />
          ))
        }
      </section>
    </Layout>
  )
}

Aplique desestructuraci贸n

{porducts.map((product) => (
 <Card key={product.id} {...product} />
))}

Cuando un objeto no existe, React arroja un error y no se renderiza nada. Por ejemplo, si llamamos {data.data.category.name} dentro de un componente y el objeto data, data.category o data.category.name no existen, la pantalla se mostrar谩 en blanco. No obstante, podemos evitar que se rompa la p谩gina si utilizamos la sintaxis opcional de encadenamiento de operadores de navegaci贸n segura, representada por el s铆mbolo ?., de esta forma: {data.data?.category?.name}. En este caso, si alguno de los objetos no existe, la expresi贸n devolver谩 undefined, pero el c贸digo seguir谩 ejecut谩ndose sin problemas. Esto puede resultar muy 煤til si la API no devuelve informaci贸n para algunos productos y queremos evitar que la p谩gina se rompa por completo.

As铆 voy con Nextjs, creo que est谩 bonito.

Yo me arm茅 un archivo para los endpoints y me hice un hook 鈥榰seFetch鈥

import { useEffect, useState } from 'react';

export const useFetch = apiUrl => {
	const [data, setData] = useState();

	useEffect(() => {
		fetch(apiUrl)
			.then(res => res.json())
			.then(data => setData(data));
	}, [apiUrl]);

	return data;
};

El Home me queda as铆:

import { productsApi } from '../../Assets/ApiUrls';
import { Card } from '../../Components/Card/Card';
import { Layout } from '../../Components/Navbar/Layout/layout';
import { useFetch } from '../../Hooks/UseFetch';

export const Home = () => {
	const data = useFetch(productsApi);

	return (
		<Layout>
			{data?.map(product => (
				<Card key={product?.id} title={product?.title} category={product?.category} price={product.price} image={product.image} />
			))}
		</Layout>
	);
};

Madre mia, hace al menos un mes que dej茅 el curso por la mitad鈥 Pero desde luego lo que he visto hoy no me parece serio. Le pasa una prop data a card y para recibirla utiliza data.data en vez de desestructurar props en {data} , igualmente si no quiere desestructurarla deberia de llamar a props.data por convenci贸n鈥

Hola comunidad, les comparto mis apuntes en Notion sobre cards y llamado a API麓s, espero les sean de utilidad.
Link aqu铆:
https://bg99astro.notion.site/Cards-y-llamado-a-API-s-b5be45bca26e48a99a25ffb9b650e383

La fakeapi de platzi me esta dando errores, asi que use la api de fake store api, funciona bastante similar a la api de platzi, asi que no hay que hacer muchos cambios.

fake store api

Si quieren hacer su propia API con endpoints y todas las configuraciones que deseen, pueden hacerla localmente con json server y hacer el deploy con Render. Es super f谩cil, les dejo un tutorial, est谩 ingles, pero funciona bien:
https://www.youtube.com/watch?v=EcxYcpF3W7c y se adjunta un repo de ejemplo: https://github.com/Md-Irfan-FullStackDeveloper/test_api
Hagan el ejemplo y luego para actualizarla solo tienen que hacer un commit y push a la misma rama, ya que render se conecta con github y en pocos minutos su url se actualiza. Sigan la estructura de la Fake API de Platzi para que no tengan errores de undefined en su c贸digo o si cambian la estructura, no se olviden de adaptar el c贸digo.
En el archivo db.json que creen:

{
  "products": [
  {
    "id": 1,
    "title": "Handmade Fresh Table",
    "price": 687,
    "description": "Andy shoes are designed to keeping in...",
    "category": {
      "id": 5,
      "name": "Others",
      "image": "https://placeimg.com/640/480/any?r=0.591926261873231"
    },
    "images": [
      "https://placeimg.com/640/480/any?r=0.9178516507833767",
      "https://placeimg.com/640/480/any?r=0.9300320592588625",
      "https://placeimg.com/640/480/any?r=0.8807778235430017"
    ]
  },
  {
    "id": 2,
    "title": "Handmade Fresh ",
    "price": 687,
    "description": "Andy shoes",
    "category": {
      "id": 5,
      "name": "Others",
      "image": "https://placeimg.com/640/480/any?r=0.591926261873231"
    },
    "images": [
      "https://placeimg.com/640/480/any?r=0.9178516507833767",
      "https://placeimg.com/640/480/any?r=0.9300320592588625",
      "https://placeimg.com/640/480/any?r=0.8807778235430017"
    ]
  },
  	.
  	. El Resto de Productos
  	.
  ],
  "categories": [
  {
    "id": 1,
    "name": "Clothes",
    "image": "https://api.lorem.space/image/fashion?w=640&h=480&r=4278"
  },
  {
    "id": 2,
    "name": "Electronics",
    "image": "https://api.lorem.space/image/fashion?w=640&h=480&r=4278"
  },
	.
	. El Resto de Categorias
	.
  ]
}

mobile-first & lazy-loading

para hacer nuestro home mobile first basta con agregar una linea de c贸digo en tailwind: gid-cols-2, quedar铆a nuestro div de la siguiente manera

grid gap-4  grid-cols-2 sm:grid-cols-4 w-full max-w-screen-lg px-2

ahora para mejorar el rendimiento de nuestra aplicaci贸n deberiamos aplicar el lazy-loading, esto lo logramos de una manera muy sencilla, instalaremos el siguiente paquete
npm i react-lazy-load-image-component

  • luego en nuestra card importamos lo siguiente
import {LazyLoadImage} from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';

y reemplazamos la etiqueta img por la etiqueta LazyLoadImage incluyendo un height, un width y un effect, quedando de la siguiente manera

<LazyLoadImage className='w-full h-full object-cover rounded-lg'
             src={data.data.url} alt={data.data.name} effect='blur' height={'100%'} width={'100%'} />

dentro de los efectos tienes blur, black-and-white y opacity, usa el que desees y no olvides importarlo de css como lo hicimos con blur, de esta manera ya tenemos aplicado el lazy-load en nuestro componente card y hemos mejorado el performance de nuestra aplicaci贸n, as铆 como tambien hemos aplicado la buena tecnica del mobile-first

En caso de que quieran hacer el grid full responsive usen las siguientes clases de tailwindcss

<section className='grid place-items-center gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 w-full max-w-screen-xl'>
      {items?.map((item) => (
        <Card key={item.id} item={item} />
      ))}
    </section>

Una aclaraci贸n sobre el array que se pasa como segundo argumento (array de dependencias) al useEffect:
Este array le dice a React qu茅 variables debe observar para determinar si el efecto debe ejecutarse nuevamente. Si alguna de las variables dentro del array de dependencias cambia su valor, React ejecutar谩 el efecto nuevamente. Si las variables no cambian, React omitir谩 la ejecuci贸n del efecto.

Algo que no me qued贸 claro es, por qu茅 en el min 18:56 se debe introducir

data.data.category.name 

para obtener el nombre del art铆culo, osea, por qu茅 dos veces data?

Usando la API de Fake Store debido a problemas con la de Platzi, asi me quedo.

Nose porque no me esta recorriendo el map. solo me muestra un producto.

si ponene le data dentro de corchetes no deben usar el data.data

const Card = ({data}) => {
 return (
  <div className='bg-white cursor-pointer w-56 h-60 rounded-lg'>
   <figure className='relative mb-2 w-full h-4/5'>
    <span className='absolute bottom-0.5 left-0 bg-white/60 rounded-lg text-black text-xs ml-1 px-1'>{data.category.name}</span>
    <img className='w-full h-full object-cover rounded-lg' src={data.images[0]} alt={data.title} />
    <div className='absolute top-0.5 right-0.5 flex justify-center items-center bg-white rounded-full w-5 h-5 font-bold pb-0.5'>+</div>
   </figure>
   <span className='flex justify-between'>
    <p className='text-sm font-light'>{data.title}</p>
    <p className='text-sm font-medium'>{'$'+data.price}</p>
   </span>
  </div>
 );
};

Personalmente le agregue un Loader de la libreria React Spinners (https://mhnpd.github.io/react-loader-spinner/docs/intro). Por si hay un retraso en la llamada a la API.

useState

Muy buena explicaci贸n de API.

As铆 vamos鈥

Hice un Loading Skeleton de la Card, dejo el link de la previsualizaci贸n

Soy mas apegado a usar async/await en vez de promises. As铆 quedo el useEffect en mi c贸digo.

  useEffect(() => {
    const getProducts = async () => {
      try {
        const data = await fetch('https://api.escuelajs.co/api/v1/products')
        const jsonData = await data.json()
        setItems(jsonData)
      } catch (error) {
        console.log(error)
      }
    }
    getProducts()
  }, [])

La API de platzi tiene muchos problemas con las im谩genes. Les recomiendo que hagan el curso usando esta API: https://fakestoreapi.com/

F铆jense en la documentaci贸n de la API para que sepan las cosas que cambian al momento de consumir y renderizar las propiedades del objeto que nos devuelve.

https://dummyjson.com/ Es una muy buena alternativa a la api de platzi, la recomiendo, esta muy completa!.

Para organizar todo mejor cree un custom hook llamado 鈥渦seFetch鈥. No lo hice yo, lo saqu茅 de https://javascript.plainenglish.io/react-creating-usefetch-custom-hook-d123ebfd5ff.

Adem谩s hice un contexto llamado 鈥淧roductsContext鈥 el cual usa este hook.

creo que deber铆an quitarle la opci贸n a la fakeapi de eliminar los productos, porque probando el api con postman solo existe un producto en el momento en que estoy viendo el curso, al parecer vandalizan mucho este api

Esta es version trabajada con typescript-

Home

import {useState, useEffect} from "react"
import { Layout } from "../../Components/Layout"
import { Card } from "../../Components/Card"

interface MyData {
  id: number;
  title: string;
  price: number;
  description: string;
  category: {
    id: number
    name: string
    image: string
  }
  images: string[]
}

const Home = () => {
  const [items, setItems] = useState<MyData[]>([])

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://api.escuelajs.co/api/v1/products')
        const data = await response.json()
        setItems(data)
      } catch(error) {
        console.error(error);
      }
    }
    fetchData()
  }, [])
  return (
    <Layout>
      Home
      {items?.map((item) => (
        <Card key={item.id} {...item}/>
      ) )}
      
    </Layout>
  )
}

export {Home}

card

interface MyData {
  id: number;
  title: string;
  price: number;
  description: string;
  category: {
    id: number
    name: string
    image: string
  }
  images: string[]
}


const Card = (data: MyData) => {
  return (
    <div className='bg-white cursor-pointer w-56 h-60 rounded-lg'>
        <figure className='relative mb-2 w-full h-4/5'>
            <span className="absolute bottom-0 left-0 m-2 bg-white/60 rounded-lg text-black text-xs px-3 py-0.5">
              {data.category.name}
            </span>
            <img className="w-full h-full object-cover rounded-lg" 
            src={data.images[0]} alt={data.title} />
            <div className="absolute top-0 right-0 flex justify-center items-center bg-white m-2 w-6 h-6 rounded-full">
                +
                </div>
        </figure>
        <p className="flex justify-between">
            <span className="text-sm font-light">{data.title}</span>
            <span className="text-lg font-medium">${data.price}</span>
        </p>
    </div>
  )
}

export {Card}

Hola, ya solo hay 2 productos como respuesta del API

![](https://static.platzi.com/media/user_upload/image-b3ab3eee-5a7b-4e39-aab5-58b8386d882b.jpg)
Pregunta 驴puedo tener almacenados los productos en un servicio como firebase? y de ser as铆, 驴c贸mo se conecta?
Es mejor deconstruir los props de para que en Card no tengas que hacer data.data, eso se hace f谩cil desde el mismo componentes con `const Card({data}) => {}` Es m谩s natural leerlo as铆

Yo personalmente trabaje las clases del div que contiene las cartas ya que al hacer resize o verse en diferentes dispositivos las cartas se sobreponen una encima de otra y dem谩s.
Para ello genere un archivo index.css para el Home el cual contiene el siguiente c贸digo.

.container_cards{
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    gap: 30px;
    width: 95%;
    justify-items: center;
}

Esto hace que no tengamos que usar un media-query para ir cambiando las columnas que tienen que generarse, sino que depende de la pantalla estas se acomodoran automaticamente.

Ahora al hacer esto toca pensar que el navbar tenemos que modificarlo si tambi茅n queremos que se vea bien desde un dispositivo mas peque帽o.

ome un hook personalizado que publico compa帽ero y lo integre, este recibe un par谩metro que es la url del endponit

import { useEffect, useState } from 'react';
export const useFetch = (url) => {
	const [data, setData] = useState();
	useEffect(() => {
		fetch(url)
			.then(res => res.json())
			.then(data => setData(data));
	}, [url]);

	return data;
};


cree un archivo para la ruta de la api y poder acceder a los diferentes endpoint

// Defin铆 UrlApi como un objeto en lugar de un array. Esto permitir谩 acceder a UrlApi.getProduct de manera adecuada.
const UrlApi = {
    getProduct: 'https://fakestoreapi.com/products',
};
export default UrlApi;

Asi Vamos, con la Fake Store API

Me qued贸 asi:


Buenas, queria compartir mi callback del useEffect que lo hice un poco distinto. A mi me gusto mas de esta forma:

  useEffect(() => {
    const getProducts = async () => {
      const response = await fetch('https://api.escuelajs.co/api/v1/products');
      const data = await response.json();
      
      setItems(data);
      console.log(items);
    };
    getProducts();
  }, []);

La API de FakeStore no es disponible 馃槕

Hola la API de platzi no ha estado funcionando bien. Puedes usar este peque帽o servidor si gustas para consumir una API desde tu propia computadora.
https://github.com/FranciscoJSB12/Ecommerce-backend
Te dej茅 un readme con las instrucciones para usarlo, as铆 podr谩s seguir con tu curso normalmente, son bastantes sencillas.

Para que quede un poco m谩s est茅tico pueden usar la destructuracion

const Card = ({ data: { title, price, category, images } }) => {
  

Prefer铆 usar async await y try catch por recomendaci贸n de un compa帽ero, ya que es lo que se recomienda al usar APIs馃槄

Pero tambi茅n me pareci贸 buena idea para practicar y repasar asincronismo en JavaScript
.
Algo que se me ocurri贸 fue hacer un condicional ternario que muestre los productos en funci贸n de si existen o no.
![](

Estoy armando una pricing page, en este caso no use el API de platzi, sin embargo le paso los datos de la siguiente manera


const data_princing_cards = [
  {
  'id':1,
  'plan':'Free',
  'benefits':['Benefit 1', 'Benefit 2', 'Benefit 3'],
  'price':10,
  },
  {
  'id':2,
  'plan':'Hobby',
  'benefits':['Benefit 1',  'Benefit 3'],
  'price':20,
  },
  {
  'id':3,
  'plan':'Standard',
  'benefits':['Benefit 1', 'Benefit 2', 'Benefit 3'],
  'price':30,
  },

]

function Pricing() {
  const [items, setItems] = useState(null)

  useEffect(() => {
    setItems(data_princing_cards)
  }, [])

Esta es mi tiendo: https://store-practice-dr.netlify.app/

馃槂

Que mal, no me salen los 200 productos 馃槶馃様

Yo llevo mi ecommerce as铆, pero con flexbox.
No s茅 por qu茅 se me dificulta m谩s con grid.

Esto es asombroso!

Hay problemas con la API, no sale bien la informacion, la imagen no corresponde a la informacion y en la mitad de la pagina ya no sale informacion

Para las personas que les gusta usar Async/Await

  useEffect(() => {
    async function fetchProduct() {
      const response = await fetch("https://api.escuelajs.co/api/v1/products");
      const data = await response.json();
      setProducts(data);
    }

    fetchProduct();
  }, []);

Que hermoso es TailwindCSS, hay alg煤n curso?

Para usar axios solo debemos importarlo
npm install axios y luego usarlo en el useEffect
useEffect(() => {
const apiUrl = 鈥https://tu-url-de-api.com/鈥;

axios.get(`${apiUrl}activos`)
  .then(response => {
    setAssets(response.data);
  })
  .catch(error => {
    console.error('Error fetching assets:', error);
  });

}, []);

Este curso me tiene muy contento, nunca habia consumido una API tan rapido y entendiendo tanto !!

Una pena que la api la est茅n modificando constantemente entorpeciendo el resultado final. Literalmente tuve que buscar una api externa para poder seguir

)

No entiendo porque los productos son tan random鈥 aveces inapropiados para presentar este proyecto como parte de mi portafolio. Habra alguna forma de arreglarlo? Una soluci贸n que pienso ahora para mi proyecto es agregar productos a una categoria creada por mi.
. Alguien tiene alguna recomendaci贸n de como solucionar esto?
.
Imagen de categoria electronicos.

.
Detalle de producto

.
Productos agregados al carrito

Card component

const Card = ({ product }) => {
  const { category, images, title, price } = product

  return (
    <div className="bg-white cursor-pointer w-56 h-60 rounded-lg">
      <figure className="relative mb-2 w-full h-4/5">
        <span className="absolute bottom-0 left-0 bg-white/60 rounded-lg text-black text-xs m-2 px-3 py-0.5">
          {category.name}
        </span>
        <img className="w-full h-full object-cover rounded-lg" src={images[0]} alt={title} />
        <div className="absolute top-0 right-0 flex justify-center items-center bg-white w-6 h-6 rounded-full m-2  p-1">
          +
        </div>
      </figure>
      <p className="flex justify-between">
        <span className="text-sm font-light">{title}</span>
        <span className="text-lg font-medium">${price}</span>
      </p>
    </div>
  )
}

export default Card

Qued贸 genial! por ahora solo me trae 20 elementos !

https://api.escuelajs.co/api/v1/products