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 鈥榟tml鈥), 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 鈥榤ap鈥. 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 鈥榤ap鈥 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 鈥渆fecto鈥), 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 鈥渕ontar鈥 y 鈥渁ctualizar鈥, puede resultarte m谩s f谩cil pensar en efectos que ocurren 鈥渄espu茅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.