¿Dónde estoy haciendo mal uso de ganchos / Estado con geolocalización en reaccionar nativa?

SuperHanz98:

Tengo un componente que se supone que debe registrar la longitud / latitud / marca de tiempo a intervalos regulares.

Cuando el usuario presiona START, el seguimiento debe comenzar. Cuando el usuario prensatelas STOP, el seguimiento debe parar.

Para implementar esto, yo he construido la siguiente (soy un principiante para reaccionar y JS así que esto podría ser del todo el camino equivocado para hacer esto):

const Tracking = props => {

  const [currentLatitude, setCurrentLatitude] = useState(0);
  const [currentLongitude, setCurrentLongitude] = useState(0);
  const [currentTimestamp, setCurrentTimestamp] = useState(0);

  const [buttonTitle, setButtonTitle] = useState('Start');
  const [isTracking, setIsTracking] = useState(false);
  var getLocationInterval;


  function getLocation() {
    navigator.geolocation.getCurrentPosition(
      position => {
        setCurrentLongitude(position.coords.longitude);
        setCurrentLatitude(position.coords.latitude);
        setCurrentTimestamp(position.timestamp);
      },
      error => alert(error.message),
      { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
    );
    console.log(currentTimestamp, currentLatitude, currentLongitude);
  };

  function startStop() {
    if(!isTracking){
      //START
      setIsTracking(true);
      getLocationInterval = setInterval(getLocation, 500);
      setButtonTitle('Stop');
    }
    else{
      //STOP
      setIsTracking(false);
      clearInterval(getLocationInterval);
      setButtonTitle('Start');
    }
  };


  return (
    <View style={{width: '100%', height: '100%'}}>
      <MapView showsUserLocation style={{flex: 1}} />
      <MenuButton title = {buttonTitle} onPress={startStop}/>
    </View>
  );

}

Comportamiento esperado : una vez que se pulsa START, el texto del botón cambia a STOP. Y en mi consola, que empezar a obtener una salida cada 500 ms con la última / tiempo / fecha y hora lat. Cuando se pulsa STOP, el texto del botón cambia a START y la parada de salidas.

El comportamiento real : una vez que se pulsa START, el texto del botón cambia correctamente para parar, pero sólo los estados iniciales (0s) son repetidamente salida. Cuando a continuación, pulse la tecla STOP, los próximos Lat Long / Inicia / indicación de la hora de ser repetidas ocasiones a la consola. Los 0s están siendo también sigue de salida ya que el intervalo no parece detenerse.

Supongo que sólo estoy usando estado completamente mal aquí. Por favor alguien me puede ayudar?

Zachary Haber:

Por lo tanto, hay algunos problemas en la forma en que ha establecido que desde el punto de vista de la lógica. Creo que lo he arreglado todos los problemas que he visto en el código de abajo.

La razón por la cual se estaba imprimiendo sólo 0 se debe a la currentLatitude / currentLongitude / CurrentTimestamp que se está haciendo referencia en la función getLocation tuvo un cierre alrededor de ella una vez que se inició el intervalo en el que no se actualizaría a la nueva versión de la función que se creó en cada re-render. Para hacer frente a esto, me quita las referencias a las variables de la función getLocation en los cambios que hice.

La razón por la que todavía había 0s que se emite es debido a que el getLocationInterval se establece en indefinido en todas las render. Hubieras tenido que hacer que sea una referencia o una variable de estado con el fin de conseguir que para mantenerse entre vuelve a renderizar.

Moví la lógica de la función de startstop en un gancho useEffect ya que es la forma correcta de hacer un efecto se produce desde el interior de un componente de gancho. También permite que toda la lógica para combinar en un solo lugar sencillo que se puede extraer de un gancho a medida con bastante facilidad si hay que usarla en otros lugares.

const Tracking = props => {
const [currentLatitude, setCurrentLatitude] = useState(0);
const [currentLongitude, setCurrentLongitude] = useState(0);
const [currentTimestamp, setCurrentTimestamp] = useState(0);

const [isTracking, setIsTracking] = useState(false);

useEffect(() => {
    if (!isTracking) return;
    function getLocation() {
    navigator.geolocation.getCurrentPosition(
        position => {
        setCurrentLongitude(position.coords.longitude);
        setCurrentLatitude(position.coords.latitude);
        setCurrentTimestamp(position.timestamp);
        console.log(
            position.coords.longitude,
            position.coords.latitude,
            position.timestamp
        );
        },
        error => alert(error.message),
        { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
    );
    }
    let getLocationInterval = setInterval(getLocation, 500);
    return () => clearInterval(getLocationInterval);
}, [isTracking]);

return (
    <View style={{ width: '100%', height: '100%' }}>
    <MapView showsUserLocation style={{ flex: 1 }} />
    <MenuButton
        title={isTracking ? 'Stop' : 'Start'}
        onPress={() => {
        setIsTracking(!isTracking);
        }}
    />
    </View>
);
};

Supongo que te gusta

Origin http://10.200.1.11:23101/article/api/json?id=405861&siteId=1
Recomendado
Clasificación