No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripción 🔥

Aprende todo un fin de semana sin pagar una suscripción 🔥

Regístrate

Comienza en:

3D
13H
48M
3S
Curso Práctico de React.js

Curso Práctico de React.js

Oscar Barajas Tavares

Oscar Barajas Tavares

useEffect y consumo de APIs

19/30
Recursos

Aportes 45

Preguntas 18

Ordenar por:

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

o inicia sesión.

Docs de la API 👉 https://api.escuelajs.co/docs/
API para desarrollo 👉 https://api.escuelajs.co/api/v1/

useEffect es una manera de que nuestro componente de React, puede recibir nueva info, re-renderizar o cambiar su contenido, cuando una función se haya completado. Es decir, podemos controlar el momento en el cual nuestro componente tome un cierto comportamiento. Por ejemplo, en situaciones como funciones asíncronas ⇒ setTimeout o asyn y await, fetch requests o manipulaciones del DOM. Veamos un ejemplo de como usar useEffect.

Pre-configuración

Instalar axios para realizar peticiones get, también instalar el plugin de babel para manejar el asincronismo

npm install axios
npm install @babel/plugin-transform-runtime

Editemos rápidamente .babelrc

{
	"presets": [
		"@babel/preset-env",
		"@babel/preset-react"
	],
	"plugins": [
		"@babel/plugin-transform-runtime"
	]
}

Ahora si veamos como funciona.

// ProductList.jsx
import React, { useEffect, useState } from 'react';
import ProductItem from '@components/ProductItem';
import axios from 'axios';

const API = 'https://api.escuelajs.co/api/v1/products';

const ProductList = () => {
	const [products, setProducts] = useState([]);

	useEffect(async () => {
		const response = await axios(API);
		setProducts(response.data);
	}, [])

	return (
		<section className="main-container">
			<div className="ProductList">
				{products.map(product => (
					<ProductItem />
				))}
			</div>
		</section>
	);
}

En el inicio estamos importando axios para las peticiones, y creando una constante API que será la necesaria para traer información de los productos

Analicemos el componente productList. Al inicio creamos la estructura inicial de estado, en la cual guardaremos los artículos que traeremos de nuestra API. Ahora, como indicamos, useEffect es muy útil para peticiones HTTP. Para ello, creamos la función anónima que usa useEffect. Por dentro creamos la función que usara async. Dentro creamos una constante llamada response a la cual creamos la petición y guadamos el resultado de la API. A continuación, usamos setProducts para poder guardar la información nueva en products, por eso por dentro le pasamos response.data. Lo más destacable viene ahora, en el momento que pasamos un segundo argumento a useEffect.

Maneras de usar useEffect

  • Array Vacío ⇒ ejecuta el callback solamente una vez, después de que el componente sea cargado en el DOM. Es decir, solamente cuando nuestro componente este cargado en el DOM, ejecutará la función por dentro SOLO UNA VEZ y nunca más
const ProductList = () => {
	const [products, setProducts] = useState([]);

	useEffect(async () => {
		const response = await axios(API);
		setProducts(response.data);
	}, [])
}
  • Sin argumentos ⇒ cuando usemos useEffect, pero sin segundo argumento, este ejecutará dicho callback cada vez que se re-rendirece en el DOM. Es decir, cada vez que cambie cualquier valor del componente, este callback siempre se ejecuta
const ProductList = () => {
	const [products, setProducts] = useState([]);

	useEffect(async () => {
		const response = await axios(API);
		setProducts(response.data);
	},)
}
  • Array con datos ⇒ este tipo se ejecuta solamente cuando un valor de prop o state de nuestro componente cambie. Es decir, imaginemos que existe un contador interno de clicks. Cada vez que el contador indique explicita mente que un valor del componente cambió, el callback de useEffect siempre se ejecutará.
const ProductList = () => {
	const [products, setProducts] = useState([]);

	useEffect(async () => {
		const response = await axios(API);
		setProducts(response.data);
	}, [props, state])
}

Tienen relación a la manera de anterior de componentes con clase

Usar la manera de array con datos o sin datos son equivalentes a componentDidUpdate o componentDidMount. Así como indica sus nombres ⇒

  • Si el componente se actualizó, este ejecuta un callback el cual tiene cierta función. Esta manera es igual a usar useEffect con un array con datos. Es decir, ¿hay nueva info? ⇒ realiza esto cada vez que la info nueva se actualice
  • Si el componente se cargó en el DOM, un callback será ejecutado y nunca más. Esta manera es igual a usar useEffect con un array sin datos. Es decir, ¿ya está cargado? ⇒ necesito que hagas esto y después te puedes quedar dormido

Es importante que si usan:

{products.map((product) => (
          <ProductItem />
        ))}

estén utilizando ( ) en la función para regresar el jsx,
si usan { } deben utilizar la palabra return así:

{products.map((product) => {
          return <ProductItem />;
        })}

para los que vienen del futuro poner async dentro del useEffect da un error y se puede solucinar así:

useEffect(() => {
getData();
}, []);

const getData = async () => {
const response = await axios.get(API);
setProducts(response.data);
console.log(response);
};

Actualmente el useEffect no puede retornar una promesa, por ende el codigo debe ser asi:

useEffect(() => {
		const getProducts = async () => {
			const response = await axios(API);
			setProducts(response.data);
		};
		getProducts();
}, []);

Aqui los comandos compañeritos:

-npm i axios
-npm install @babel/plugin-transform-runtime

Hay algo que falto y que en React es importante, el key de cada elemento renderizado dentro del map =>

<div className="ProductList">
	{
		products.map( product => (
			<ProductItem key={ product.id } />
		))
	}
</div>

Desde 10:05 hasta 10:22 se filtra un sonido raro en el video, que miedo.

Documentación de la API: https://api.escuelajs.co/docs/

Constante de la API:

const API = 'https://api.escuelajs.co/api/v1/products';

Luego declarar las variables para el useState

const [products,setProducts] = useState([]);

Tienen que instalar axios
Documentación de axios: https://axios-http.com/docs/intro

npm install axios

Solicitud GET

useEffect(async ()=>{
	const response = await axios(API);
	setProducts(response.data);
},[])

Para recorrer el array de productos se usa el map

{products.map(product =>(
	<ProductItem />
))}

También puedes utilizar esta API
https://fakestoreapi.com/

useEffect es la forma en la manejamos el ciclo de vida de un componente, en este caso nuestro componente contenedor que contiene otros componentes (los productos).

.
Si alguna vez trabajaron con los metodos del ciclo de vida de un class component, entender esta siguiente imagen les abrira la mente a entender de una vez por todas useEffect.

.
Abajo muestro un ejemplo de mi implementacion para este ejercicio:

Ey Oscar el termo de JavaScript que tenias en el escritorio de atras ya no está 😦

  • npm install axios
  • npm install @babel/plugin-transform-runtime

Podríamos decir que en está clase vimos levemente como integrar backend con frontend.

Es importante mencionar que existe un efecto llamado useLayoutEffect, todo el código que contiene se ejecuta una vez sea renderizado el componente. A diferencia de useEffect el cual se ejecuta justo antes del render. 😀💚

Si están usando React18 o >, useEffect no puede retornar promesas y al renderizar componentes mediante una ciclo usando map les pedirá usar un id. Pueden usar este código.

  • El id se genera de manera automatica con el valor de la iteración. No es recomendable hacerlo así pero por ahora esta bien usarlo.
import React from 'react';
import { useEffect, useState } from 'react';
import {ProductItem} from '../components/ProductItem';
import '../styles/ProductList.scss';
import axios from 'axios';

const API = 'https://api.escuelajs.co/api/v1/products';

export const ProductList = () => {
	const [products, setProducts] = useState([]);

	useEffect(() => {
    getProducts()
  }, [])

  const getProducts = async () =>{
    const response = await axios(API);
    setProducts(response.data);
  };


  return (
    <section className="main-container">
			<div className="ProductList">
				{products.map((product, id)=>					
					<ProductItem key = {id}/>
				)}
			</div>
		</section>
	);
}

A mi me funciona sin instalar @babel/plugin-transform-runtime, será porque uso React 18?

Si por alguna razón no le lista los productos es mejor leer la API con fetch.

const obtenerDatos = async () => {
		const data = await fetch(API);
		const productos = await data.json();
		setProducts(productos)
	} 

Una recomendación en el curso se hace uso de axios(URL_API) como método para traer elementos de la api, pero una api posee los demás métodos para realizar un crud, como lo es con el post para crear, el delete para eliminar y el put/patch para actualizar, así que una manera de llevar legible el código sería usar de esta forma la consulta a la api

useEffect(async () => {
        const response = await axios.get(API);
        setProducts(response.data);
    }, [])

En lugar de:

    useEffect(async () => {
        const response = await axios(API);
        setProducts(response.data);
    }, [])

Comento esto porque me preguntaba como realizar un crud con react consumiendo la api, y me resultó esa duda, así que investigué la librería axios, y veo que de esa manera es que debería de usarse
Link de la documentación:
https://axios-http.com/docs/api_intro

Para los que estamos usando la ultima version de React, si no les funciona el codigo, cambien en la parte de useEffect por este codigo:

React.useEffect(() => {
async function fetchData() {
const response = await axios(API);
setProducts(response.data);
console.log(products)
}
fetchData();
console.log(products);
}, [])

y luego cuando retornan el componente (donde escriben la estructura ‘html’), coloquen:

{products.map((product) => {
return(
<ProductItem />
)
})}

con estos dos cambios deberia funcionar perfectamente

plugin babel:

npm install @babel/plugin-transform-runtime

React.UseEffect
Ejecuta el código que tengamos adentro justo antes de que React tiene todo listo para renderizar el componente

  • El segundo argumento que le enviamos al hook puede ser un array vacío [ ], este le dice al UseEffect que solo se ejecute la primera vez que el componente se renderize, cuando se rerenderize no se ejecutara. Si dejamos ese segundo argumento vacío, el hook se ejecutara todas las veces que nuestro componente se rerenderize.
  • Podemos ejecutarlo cuando hayan cambios específicos en cierta variable o cierto componente, para eso podemos poner como segundo argumento un arreglo y adentro el nombre de la variable: [TotalToDos].

React.UseLayoutEffect
Ejecuta el código que tengamos adentro justo después de que React renderizo el componente

Para manejar los estados de request hacia una API:
Se necesitan 3 estados de carga:

  1. Estamos cargando tu información
  2. Ya cargamos tu información pero tiene hubo un error
  3. Ya cargamos tu información y todo esta perfecto

El usar useEffect, con un arreglo vacío, es decir sin ninguna dependencia, es igual que cuando se usa componentDidMount en un class component.

useEffect(() => { ... }, []) === componentDidMount

Para que se ahorren el código del Lazy Loading. Ahora en nativo en HTML

<img src={product.images[0]} alt={product.name} loading="lazy" />

Para los que estén trabajando con Ts y quieran tipar de manera sencilla la api, usen app.quicktype.

Les comento que a mi no me renderizaban los elementos, sí lograba traer los datos de la API pero aún así no renderizaba.
Resulta que el problema estaba en la sintáxis de mi método ‘map’. Recuerden que siempre que usan llaves {…} para su arrow function, dentro debe haber un return. Mi problema era que no tenía un return y por eso ‘map’ no devolvía nada.

<div className="cards-container">

        {products.map( product => {
          return <ProductItem key={ product.id }/>
        }) }

</div>

¿Qué hace useEffect? Al usar este Hook, le estamos indicando a React que el componente tiene que hacer algo después de renderizarse. React recordará la función que le hemos pasado (nos referiremos a ella como nuestro “efecto”), y la llamará más tarde después de actualizar el DOM. En este efecto, actualizamos el título del documento, pero también podríamos hacer peticiones de datos o invocar alguna API imperativa.
¿Por qué se llama a useEffect dentro del componente? Poner useEffect dentro del componente nos permite acceder a la variable de estado count (o a cualquier prop) directamente desde el efecto. No necesitamos una API especial para acceder a ella, ya que se encuentra en el ámbito de la función. Los Hooks aprovechan los closures de JavaScript y evitan introducir APIs específicas de React donde JavaScript ya proporciona una solución.
¿Se ejecuta useEffect después de cada renderizado? ¡Sí! Por defecto se ejecuta después del primer renderizado y después de cada actualización. Más tarde explicaremos cómo modificar este comportamiento. En vez de pensar en términos de “montar” y “actualizar”, puede resultarte más fácil pensar en efectos que ocurren “después del renderizado”. React se asegura de que el DOM se ha actualizado antes de llevar a cabo el efecto.
Fuentes: https://es.reactjs.org/docs/hooks-effect.html

al dia de hoy la api no esta regresando algunas imagenes, es problema de la api , de momento de mi aporte para que pongan una condición si no hay imagen que no se renderize el componente PorducItem

return (
    <>
      {product.images[0] !== "" ? (
        <div className='ProductItem'>
          <img src={product.images[0]} alt={product.title} />
          <div className='product-info'>
            <div>
              <p>${product.price}</p>
              <p>{product.title}</p>
            </div>
            <figure onClick={() => handleClick(product)}>
              {state.cart.includes(product) ? (
                <img
                  className='disabled add-to-cart-btn'
                  src={addedToCartImage}
                  alt='added to cart'
                />
              ) : (
                <img
                  className='add-to-cart-btn pointer'
                  src={addToCartImage}
                  alt='add to cart'
                />
              )}
            </figure>
          </div>
        </div>
      ) : (
        <></>
      )}
    </>
  )
}

Por si las Flys

{
    "presets": [
      "@babel/preset-env",//Permite trabajar con eMAC 5 EMAC6 
      "@babel/preset-react"//Permite trabajar con React en sus nuevas y viejas versiones 
    ],
    "plugins":[
      "@babel/plugin-transform-runtime"
    ]
  }

Si a alguien le da error al instalar el plugin, intenten añadiéndole “” después de install.

A mi me funcionó de esta manera:

npm install “@babel/plugin-transform-runtime”

el que tenga este error y no sepa que hacer instale este plugin https://www.npmjs.com/package/node-polyfill-webpack-plugin y el que si sepa porfa me dicen porque pasa y si es la mejor solucion?


BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. This is no longer the case. Verify if you need this module and configure a polyfill for it.

Para tener en cuenta en caso de tener que llamar apis o peticiones cuya respuesta pueda llegar a tardar, dentro de un useEffect:

  • Lo que renderiza no lo agrega al código fuente, lo que genera problemas al no permitir que google indexe el mismo.
  • Si llamo una api que tarda mucho, el cliente va a ver una página en blanco hasta recibir el contenido.

Me parece genial que practiquemos como se puede consumir una api en este curso de react

Si no quieren instalar otra dependencia para usar async y await pueden usar esta configuración en su .babelrc 😄:

{
    "presets": [["@babel/preset-env", { "targets": { "node": "11" } }], "@babel/preset-react"]
}

Si le sale varios errores como a mi, por error en el identificador de los objetos dentro del array y por el performance de async y await, aca les dejo la solucion

import React, {useState, useEffect} from 'react';
import axios from 'axios';
import ProductItem from '@components/ProductItem';
import '@styles/ProductList.scss';

const API = 'https://api.escuelajs.co/api/v1/products';

const ProductList = () => {
	const [products, setProducts] = useState([]);

	useEffect(()=>{
		const getProducts = async () => {
			const response = await axios(API)
			setProducts(response.data);
		}
		getProducts();

	},[]);


	return (
		<section className="main-container">
			<div className="ProductList">
				{products.map(product => (
					<ProductItem key={product.id}/>
				))}
			</div>
		</section>
	);
}

export default ProductList;

por conocimiento de otros cursos en ves de utilizar axios ando realizando las llamadas con fetch y asi practico mas, axios lo estube utilizando en su momento en produccion y traia mucha incompatibilidad.

No me gusta usar axios la verdad, con el simple pero poderoso fetch es mas que suficiente

useEffect(async () => {
    const req = await fetch(URL_API)
    const resp = await req.json()
    setProducts(resp)
  }, [])

Para los que estan usando Typescript
Aqui el useEffect,PD: es con funcion anonima:

  useEffect(() => {
    (async (): Promise<any> => {
        const rta = await axios(API);
        setProducts(rta.data);
    })();
  }, []);
  

si no aparecen los productos y copiaron el codigo de Oscar tal vez el problema sea este

{products.map((product) => (
          <ProductItem />
        ))}

The useEffect Hook allows you to perform side effects in your components.

Some examples of side effects are: fetching data, directly updating the DOM, and timers.

useEffect accepts two arguments. The second argument is optional.

useEffect(<function>, <dependency>)

++Example:
++

import { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
    }, 1000);
  });

  return <h1>I've rendered {count} times!</h1>;
}

ReactDOM.render(<Timer />, document.getElementById('root'));

Ya no está disponible la API. Arroja error 404.

Ahora entiendo porque usan react:
Cuando hice este codigo dije, esto es lo mismo que se hacia en php.

<div className="ProductList">
				{
					products.map(product => (
						<ProductItem />
					))
				}
			</div>
					

Ya les cache a los de react developers, creo que tuvieron algún pasado con php jaja.