Estoy haciendo un Carrusel que cuando abre una "noticia" puedes ver una descripción en un modal, eso funciona perfecto, pero cuando haces clic en una oferta te redirige a otra página con la información sobre ese producto.
Está funcionando, pero cuando lo hace, en la consola muestra el error de pérdida de memoria "react-dom.development.js:67 Advertencia: no se puede realizar una actualización de estado de React en un componente desmontado. Esto no es operativo, pero indica una pérdida de memoria en su aplicación. Para solucionarlo, cancele todas las suscripciones y tareas asincrónicas en una función de limpieza useEffect".
Sé usar useEffect y no sé cómo evitar esto.
Gracias por tu tiempo
Esta es la "AxiosCollection"
import axios from "axios"; const baseURL = "http://localhost:8080"; function AxiosGetData(url, setData) { axios .get(`${baseURL}${url}`, { headers: { "Content-type": "application/json", }, }) .then((response) => { setData(response.data); }) .catch((error) => { return error; }); } export { AxiosGetData }; import React, { useState, useEffect } from "react"; import { AxiosGetData } from "../AxiosCollection/AxiosCollection"; import Modal from "../Modal/Modal"; import { Link } from "react-router-dom"; // Import Swiper React components import { Swiper, SwiperSlide } from "swiper/react"; // Import Swiper styles import "swiper/swiper-bundle.min.css"; import "swiper/swiper.min.css"; import BenefitCard from "../BenefitCard/BenefitCard"; //Css file import "./Slider.css"; // import Swiper core and required modules import SwiperCore, { Pagination, Navigation } from "swiper"; // install Swiper modules SwiperCore.use([Pagination, Navigation]); const Slider = () => { //state to populate with featured object from API const [featured, setFeatured] = useState([]); const [isOpen, setIsOpen] = useState(false); const [featuredById, setFeaturedById] = useState(); const onCloseRequest = () => setIsOpen(false); // hook to fetch data with Axios,it only runs once, takes an url and a function as params const handleClick = (item) => { AxiosGetData(`/jp-coin/featured/${item.featuredId}`, setFeaturedById); setIsOpen(true); }; useEffect(() => { AxiosGetData("/jp-coin/featured", setFeatured); }, []); return ( <Swiper slidesPerView={1} spaceBetween={30} slidesPerGroup={1} loop={true} loopFillGroupWithBlank={true} pagination={{ clickable: true }} navigation={true} breakpoints={{ 768: { slidesPerView: 3, spaceBetween: 30, slidesPerGroup: 3, }, }} className="mySwiper" > {featured.map((item) => ( <SwiperSlide key={item.featuredId} onClick={() => handleClick(item)}> <Link to={item.type === "offer" ? `/jp-coin/offers/${item.featuredId}` : "/"}> <BenefitCard benefit={item} /> </Link> </SwiperSlide> ))} {featuredById && featuredById.type === "news" && ( <> <Modal isOpen={isOpen} onCloseRequest={onCloseRequest} className="slider__modalContainer" > <img src={featuredById.image} alt={featuredById.title} /> <h1 className="slider__modalTitle">{featuredById.title}</h1> <p className="slider__modalDescription"> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Hic blanditiis aperiam fuga ex, ratione recusandae ut harum, nam doloremque veniam necessitatibus, fugiat delectus placeat possimus totam sequi. Minus, at vitae. </p> </Modal> </> )} ; </Swiper> ); }; export default Slider; .swiper { height: 100%; width: 100%; } .swiper-slide { font-size: 18px; text-align: center; /* Center slide text vertically */ -ms-flex-align: center; -ms-flex-pack: center; -webkit-align-items: center; -webkit-box-align: center; -webkit-box-pack: center; -webkit-justify-content: center; align-items: center; display: -ms-flexbox; display: -webkit-box; display: -webkit-flex; display: flex; justify-content: center; } .swiper-slide img { display: block; height: 100%; object-fit: cover; width: 100%; } .swiper-slide p { height: 22px; width: auto; } .swiper-button-next, .swiper-button-prev { background: rgba(0, 0, 0, 0.5); color: var(--primary-color-green); } .swiper-pagination-bullet-active { background: var(--primary-color-green); } .slider__modalContainer { position: relative; } .slider__modalTitle { background-color: rgba(0, 0, 0, 0.5); color: white; font-size: 26px; padding: 0 8px; position: absolute; top: 80px; } .slider__modalDescription { background-color: rgba(0, 0, 0, 0.5); bottom: 30px; color: white; font-size: 18px; padding: 0 8px; position: absolute; }Creo que su problema puede provenir de handleClick y no de useEffect . Cuando hace clic en cualquiera de sus elementos (independientemente de si tiene el tipo "noticias" u "oferta"), su controlador de clic llamará a AxiosGetData y luego intentará realizar actualizaciones de estado ( setFeatureById y setIsOpen ) para mostrar el modal. Pero para los elementos de "oferta", también está redirigiendo a una página de detalles, por lo que su componente Slider se desmonta antes de que se produzcan las actualizaciones de estado, lo que probablemente explica por qué recibe la advertencia de pérdida de memoria. Si desea evitar que se produzcan actualizaciones de estado para elementos de "oferta", puede cambiar handleClick a:
const handleClick = (item) => { if (item.type === 'news') { AxiosGetData(`/jp-coin/featured/${item.featuredId}`, setFeaturedById); setIsOpen(true); } };Eso sucede porque está intentando actualizar el estado de forma asíncrona y la actualización podría ocurrir cuando el componente está desmontado.
Puede mantener una referencia que verificará si el componente está montado o no, como en el código a continuación.
Debido a que no puedo ver la implementación de AxiosGetData , puede verificar si ref es verdadera, cuando consumirá la promesa de axios.
const isMountedRef = useRef(); useEffect(() => { isMountedRef.current = true // In your async function check is the isMountedRef is true or not AxiosGetData("/jp-coin/featured", setFeatured); return () => { isMountedRef.current = false } }, []);Por ejemplo, usando la búsqueda regular, podría lograrlo así:
const isMountedRef = useRef(); useEffect(() => { isMountedRef.current = true; fetch('someAPIDomain').then(data => { isMountedRef.current && setState(data); }); return () => { isMountedRef.current = false } }, []);