Jan Jankowski
Jan Jankowski

Reputation: 165

interval not cleared in react useEffect

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.

Upvotes: 1

Views: 55

Answers (1)

Wraithy
Wraithy

Reputation: 2056

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 (
        <>
        </>
    );
};

Upvotes: 1

Related Questions