interval not cleared in react useEffect

Viewed 35

I have this component:

export const Widget: FC<IWidgetProps> = ({ appid, flavor, showWidgetField, updateSpeed }) => {
    const { state: geocodingState } = useContext(GeocodingContext);
    const { dispatch: weatherDispatch } = useContext(WeatherContext);

    const fetchCb = useCallback(() => {
        if (geocodingState.coords) getWeatherInfo(weatherDispatch)(appid, geocodingState.coords.lon, geocodingState.coords.lat);
    }, [geocodingState.coords]);

    useEffect(() => {
        let interval: NodeJS.Timeout | null = null;
        if (!interval) {
            interval = setInterval(fetchCb, updateSpeed);
        } else {
            if (!geocodingState.coords) clearInterval(interval);
        }
        return () => {
            if (interval) clearInterval(interval);
        }
    }, [geocodingState.coords]);

    return (
        <>
        </>
    );
};

Unfortunately, the interval does not get cleared when the geocodingState.coords is nullified nor in the useEffect return.

1 Answers

Because everytime you change geocodingState.coords, you creating new interval.... and the previous one is still running. Best solution for this is to save interval in useState, because othervise, your code doesnt know ID of interval, that needs to be cleared.

export const Widget: FC<IWidgetProps> = ({ appid, flavor, showWidgetField, updateSpeed }) => {
    const { state: geocodingState } = useContext(GeocodingContext);
    const { dispatch: weatherDispatch } = useContext(WeatherContext);
    const [intervalId, setIntervalId] = useState();
    const fetchCb = useCallback(() => {
        if (geocodingState.coords) getWeatherInfo(weatherDispatch)(appid, geocodingState.coords.lon, geocodingState.coords.lat);
    }, [geocodingState.coords]);

    useEffect(() => {
        
        if (!intervalId) {
            interval = setInterval(fetchCb, updateSpeed);
            setIntervalId(interval)
        } else {

            if (!geocodingState.coords) clearInterval(intervalId);
        }
        return () => {
            if (intervalId){
 clearInterval(interval);
setIntervalId(undefined);
        }
    }, [geocodingState.coords]);

    return (
        <>
        </>
    );
};
Related