I'm trying to use useMediaQuery with NextJS to conditionally render a background image, but i get "Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. "
when getStaticProps starts.
I tried to add some cleanup function, but with no results.
export const getStaticProps: GetStaticProps = async () => {
const rocketData = await fetchPlanetsInfo("technology");
return {
props: {
data: rocketData,
},
};
};
export default function Technology({ data }: Props) {
const isMobile = useMediaQuery({ query: "(max-width: 30em)" });
const [mobileView, setMobileView] = React.useState(false);
React.useEffect(() => {
setMobileView(isMobile);
}, [isMobile]);
return (
<Layout>
<MainPagesComponents
backgroundImage={spaceLaunchBackground}
title={"03 SPACE LAUNCH 101"}
>
<Swiper
// direction={"vertical"}
modules={[Pagination, Autoplay]}
spaceBetween={0}
slidesPerView={"auto"}
centeredSlides={true}
scrollbar={{ draggable: true }}
autoplay={{
delay: 5000,
pauseOnMouseEnter: true,
disableOnInteraction: false,
}}
pagination={{
clickable: true,
bulletActiveClass: "tech-active-class",
bulletClass: "swiper-tech",
horizontalClass: "swiper-tech-position-container",
renderBullet: (index, className) => {
return `
<div class='${className}'>${index 1}</div>
`;
},
}}
className="mySwiper"
>
{data.map((rocket) => {
const portraitImage = rocket.images.portrait.slice(1);
const landscapeImage = rocket.images.landscape.slice(1);
const viewImage = {
width: mobileView ? "375px" : "515px",
height: mobileView ? "170px" : "527px",
};
return (
<SwiperSlide key={uuidv4()}>
<TechnologySlider
view={viewImage}
image={mobileView ? landscapeImage : portraitImage}
title={rocket.name.toUpperCase()}
description={rocket.description}
/>
</SwiperSlide>
);
})}
</Swiper>
</MainPagesComponents>
</Layout>
);
UPDATE:
I create a simple gif where i'm recording the error, https://gifyu.com/image/SHbRd
CodePudding user response:
Is the error occurring when you call the getStaticProps function? If that's the case, you need to fix how you're returning the prop data. Maybe throw in a promise after the fetch occurs and then return the data if it's successful.
Also to clean up a function in react, the useEffect needs to return a callback function. I think just wrapping the useMediaQuery inside This callback function is run every time the component unmounts. Here's an example:
useEffect(() => {
//do something
...
//clean up
return () => {
//thing you want to clean up
}
}, [])
You can read more about it here: https://reactjs.org/docs/hooks-effect.html
CodePudding user response:
I you need to check if the render is mounted to perform state update.
here's a custom hook that helps you check if the component is mounted, you can use it as condition to run states update and avoid the error
//our custom hook
export const useIsMounted = () => {
const ref = React.useRef(false)
const [, setIsMounted] = React.useState(false)
React.useEffect(() => {
ref.current = true
setIsMounted(true)
return () => (ref.current = false)
}, [])
return () => ref.current
}
then use import it or use it on same page file
...
const isMobile = useMediaQuery({ query: "(max-width: 30em)" });
const [mobileView, setMobileView] = React.useState(false);
const isMounted = useIsMounted()
React.useEffect(() => {
//update state only if the component is mounted
if(isMounted) setMobileView(isMobile);
}, [isMobile, isMounted ]); //add it as dependency here
...