在react native中使用hook/state和geolocation哪里出错了



我有一个组件,它应该定期记录经度/纬度/时间戳。

当用户按下START时,跟踪应该开始。当用户按下STOP时,跟踪应停止。

为了实现这一点,我构建了以下内容(我是react和JS的完全初学者,所以这可能是完全错误的方法(:

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

预期行为:按下START后,按钮文本将变为STOP。在我的控制台中,我开始用最新的lat/long/timestamp每500ms获得一次输出。按下STOP时,按钮文本变为START,输出停止。

实际行为:按下START后,按钮文本将正确更改为STOP,但仅重复输出初始状态(0s(。当我按下STOP时,下一个lat/long/timestamp开始重复输出到控制台。0也仍然在输出,因为间隔似乎没有停止。

我猜我只是完全错误地使用了state。有人能帮我吗?

因此,从逻辑角度来看,如何设置它存在一些问题。我相信我已经修复了在下面的代码中看到的所有问题。

之所以只打印0,是因为一旦间隔开始,getLocation函数中引用的currentLatitude/currentLongitude/ccurrentTimestamp就会有一个闭包,它不会刷新到每次重新渲染时创建的函数的新版本。为了解决这个问题,我在所做的更改中从getLocation函数中删除了对这些变量的引用。

仍有0输出的原因是,在每次渲染中,getLocationInterval都设置为未定义。您必须将其作为引用或状态变量,以便在重新渲染之间保持不变。

我将逻辑从startStop函数移到了useEffect钩子中,因为这是从钩子组件中产生效果的正确方法。它还允许将所有逻辑组合在一个简单的位置,如果您需要在其他位置使用它,可以很容易地将其提取到自定义钩子中。

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

编辑:使用返回的说明效果:

上面代码第27行的返回函数:return () => clearInterval(getLocationInterval);

clearInterval不会立即运行,因为它是箭头函数声明的一部分。我们返回该函数,而不是直接调用它。一旦我们返回函数声明,react现在可以再次控制代码,并在需要时调用它

特别是,useEffect允许您返回用于清理的函数。它在组件卸载时或再次运行挂钩之前调用该函数(即依赖数组已更改(

官方反应文件中还有更多信息:https://reactjs.org/docs/hooks-reference.html#cleaning-提高效果

相关内容

  • 没有找到相关文章

最新更新