Im getting this error mostly while shifting components. Can anyone help me out. I have tried the abortController and mount state solution but none of them worked
Warning: 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. at FeedVideo
import { FC, useEffect, useState } from 'react';
import ReactPlayer from 'react-player';
import { FeedVideoProps } from '../../utils/types/interfaces';
import { getDecodedMedia } from '../../utils/helpers/getS3URL';
const FeedVideo: FC<FeedVideoProps> = ({ s3Key }: FeedVideoProps) => {
const [videoLink, setVideoLink] = useState<string>('');
const [isPlaying, setIsPlaying] = useState<boolean>(true);
const getURL = async (key: string) => {
const link: string | object = await getDecodedMedia(key);
setVideoLink(link as string);
};
useEffect(() => {
const abortController = new AbortController();
getURL(s3Key).then(() => abortController.abort());
return () => {
abortController.abort();
};
}, [s3Key]);
return (
<ReactPlayer
stopOnUnmount={true}
className={'react-player'}
controls={true}
url={videoLink}
playing={isPlaying}
/>
);
};
export default FeedVideo;
here is the code of the component that im using.
CodePudding user response:
I wouldn't worry much about it, since it's just a warning that React gives you when some state update happens after unmount. In your case, it is happening because getUrl
is async and after resolving it sets videoLink
.
I'm saying that you shouldn't worry too much because what is happening is that your component is unmounting and then one small operation is "leaking" (which is setVideoLink(link as string)
).
Memory leaks are worrisome when you're handling event listeners or intervals.
Even so, if you're worried about this behavior or if you're just too bothered with the warning you could create a logic that checks if your component is mounted before triggering the setState
call:
import { FC, useEffect, useState } from 'react';
import ReactPlayer from 'react-player';
import { FeedVideoProps } from '../../utils/types/interfaces';
import { getDecodedMedia } from '../../utils/helpers/getS3URL';
const FeedVideo: FC<FeedVideoProps> = ({ s3Key }: FeedVideoProps) => {
const [videoLink, setVideoLink] = useState<string>('');
const [isPlaying, setIsPlaying] = useState<boolean>(true);
const getURL = async (key: string, isMounted: boolean) => {
const link: string | object = await getDecodedMedia(key);
if (isMounted) setVideoLink(link as string);
};
useEffect(() => {
let isMounted = true;
const abortController = new AbortController();
getURL(s3Key, isMounted).then(() => abortController.abort());
return () => {
abortController.abort();
isMounted = false;
};
}, [s3Key]);
return (
<ReactPlayer
stopOnUnmount={true}
className={'react-player'}
controls={true}
url={videoLink}
playing={isPlaying}
/>
);
};
export default FeedVideo;
CodePudding user response:
const getURL = async (key: string): Promise<string> => {
try {
const link: string | object = await getDecodedMedia(key);
return (link as string) || '';
} catch (e) {
throw new Error(e);
}
};
useEffect(() => {
let feedVideoMounted = true;
getURL(s3Key).then((link) => {
if (feedVideoMounted && link) {
setVideoLink(link);
}
});
return () => {
feedVideoMounted = false;
};
}, [s3Key]);
So, i fixed the issue by changing the logic to this and it worked!