How can I solve the warning "Warning: Can't perform a React state update on an unmounted component." from setInterval function?

Viewed 180

I created my project React-Native. My project use 'expo-location' for tracking location module. I use setInterval function (inside useEffect hooks) for get last location every 10 seconds. But after I tested app, there is warning message below..

enter image description here

From warning message, I think the problem is come from setInterval function. But I try to fix but it cannot pass, because I maybe use wrong coding.

Problem component is below,

import React, { useState, useEffect, useRef } from 'react';
import Constants from 'expo-constants';

import * as Location from 'expo-location';
import io from 'socket.io-client';

import BasedModel from '../models/BasedModel';

const objBasedModel = new BasedModel;

const Tracker = () => {
  const ref = useRef();
  const [trigger, setTrigger] = useState(Date.now());
  const [trackLocation, setTrackLocation] = useState();
  const [errorMsg, setErrorMsg] = useState('');

  const submitLocation = (location) => {
    const sendMessage = {
      "latitude": location.coords.latitude,
      "longitude": location.coords.longitude
    };
    ref.current.emit('emit location', sendMessage);
  }

  useEffect(() => {
    const socket = io(objBasedModel.serverUrl);
    ref.current = socket;

    (async () => {
      if (Platform.OS === 'android' && !Constants.isDevice) {
        setErrorMsg(
          'Oops, this will not work on Snack in an Android emulator. Try it on your device!'
        );
        return;
      }
      let { status } = await Location.requestPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      let location = await Location.getCurrentPositionAsync({});
      console.log("location: ", location);
      setTrackLocation(location);
      setInterval(() => {
        submitLocation(location);
        setTrigger(Date.now());
      }, 10000);
    })();

    return () => socket.disconnect();
  }, []);

  return (
    <React.Fragment />
  );
}

export default Tracker;

How can I solve the warning "Warning: Can't perform a React state update on an unmounted component." from setInterval function by the right way?

Thanks in advance,

1 Answers

I addition to return the socket.disconnect in the clean up function, you also need to disable the interval as well. The interval in contrast to the setTimeout will be called until it is stopped with clearInterval.

useEffect(() => {
    const socket = io(objBasedModel.serverUrl);
    ref.current = socket;

    let handle = undefined
    (async () => {
      if (Platform.OS === 'android' && !Constants.isDevice) {
        setErrorMsg(
          'Oops, this will not work on Snack in an Android emulator. Try it on your device!'
        );
        return;
      }
      let { status } = await Location.requestPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      let location = await Location.getCurrentPositionAsync({});
      console.log("location: ", location);
      setTrackLocation(location);
      handle = setInterval(() => {
        submitLocation(location);
        setTrigger(Date.now());
      }, 10000);
    })();

    return () => {
           socket.disconnect();
           if(handle) clearInterval(handle);
  }, []);
Related