简体   繁体   中英

React useEffect avoid update callback in every update

Is there a way to avoid update a callback in useEffect?. For example I am subscribed an event with geofire , this listens for changes and receive locations.

I need to update my state without subscribing every time on every update.

Current behavior

  1. Subscribed to geofire and receive location (A)
  2. Update my state with the new location (A)
  3. Subscribed to geofire again and receive location (A)

this is an infinite loop. And I can't receive the other locations

Expected behavior

  1. subscribed to geofire only once and receive locations (A,B,C)
  2. update my state with the new locations (A,B,C)

import React, {useState, useEffect} from 'react';
import {View, Text} from 'react-native';
import {GeoPosition, GeoError} from 'react-native-geolocation-service';

import {getCurrentLocation, LocationInfo} from '../../util/geolocation';

import GeoFireService, {EVENT_TYPE} from './services/GeoFireService';

interface CurrentLocation {
  [key: string]: {
    location: [number, number];
    distance: number;
  };
}

const Ads = () => {
  const [locationInfo, setLocationInfo] = useState({
    latitude: 0,
    longitude: 0,
    altitude: 0,
    accuracy: 0,
  } as LocationInfo);
  const [currentLocation, setCurrentLocation] = useState({});

  // set the current location
  useEffect(() => {
    getCurrentLocation(
      (position: GeoPosition) => {
        const {latitude, longitude, accuracy, altitude} = position.coords;
        setLocationInfo({latitude, longitude, accuracy, altitude});
      },
      (err: GeoError) => {
        console.log(err);
      },
    );
  }, []);

  // get ads
  useEffect(() => {
    (async () => {
      if (locationInfo.latitude === 0 && locationInfo.longitude === 0) {
        return null;
      }

      // this must be execute only once
      await GeoFireService.queryToRadius(
        [-34.5742746, -58.4744191],
        30,
        (key: string, location: [number, number], distance: number,) => {
          // update state 
          setCurrentLocation({
            ...currentLocation,
            [key]: {location},
          });
        },
      );
    })();
  }, [locationInfo, currentLocation]);
// [locationInfo] with this option the update does not work

  return (
    <View>
      <Text>
        Latitude: {locationInfo.latitude} Longitude: {locationInfo.longitude}
      </Text>

      {Object.keys(currentLocation).map((key: string) => (
        <Text key={key}>Ubicacion: {currentLocation[key].location}</Text>
      ))}
    </View>
  );
};

export default Ads;

Have you checked if the return conditional is working on page load (just put a console log in there)?

From reading it, it seems both useEffects get called on page load, but the second one should exit immediately, and then get called again after the first one completes.

Then I notice you update state through an async call back, which may have something to do with it. It's difficult to say without seeing it in action.

I would say try rewriting your setCurrentLocation with a function rather than object:

setCurrentLocation((currentLocation) => ({
    ...currentLocation,
    [key]: {location},
}));

Maybe its not getting passed through and toggling between new and old data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM