我想在我的gps应用中计算速度,为此,我要使用状态来保存当前的前一个时间,纬度和经度。 我在useEffect中初始化了订阅函数,但是先前的时间状态lat和lon总是相同的,即使应该更新几次。如何在不使用localStorage保留这些值的情况下完成这项工作?
const [lat, setLat] = useState(51.55);
const [lon, setLon] = useState(0);
const [prevLat, setPrevLat] = useState(0);
const [prevLon, setPrevLon] = useState(0);
const [time, setTime] = useState(new Date());
const [prevTime, setPrevTime] = useState(new Date());
useEffect(() => {
Geolocation.getCurrentPosition().then((resp) => {
setTime(resp.timestamp);
setLat(resp.coords.latitude)
setLon(resp.coords.longitude)
}).catch((error) => {
console.log('Error getting location', error);
})
const onSuccess = () => {
console.log('success')
}
const onError = () => {
console.log('error')
}
let watch = Geolocation.watchPosition(onSuccess, onError, { enableHighAccuracy: true });
watch.subscribe((data) => {
if (data && data.coords && data.coords.latitude && data.coords.longitude) {
setPrevLat(lat);
setPrevLon(lon);
setPrevTime(time);
setLat(data.coords.latitude);
setLon(data.coords.longitude);
setTime(data.timestamp);
//calculate speed
console.log(calculateSpeed(prevTime, prevLat, prevLon, data.timestamp, data.coords.latitude, data.coords.longitude));
} else {
alert(data.message, ' ', data.code)
}
});
}, [])
换句话说,calculateSpeed的第4、5和6个参数是正确的值,但是prevTime,prevLon和prevLat仍然是相应的:应用程序开始运行的日期,0、0
答案 0 :(得分:2)
这是经典的函数式编程问题,您必须使用闭包来提防。
发生了什么事?
useEffect
仅在第一个渲染器上被调用,因为您有[]
作为依赖项。watch.subscribe
并创建一个 closure !该闭包可以访问父作用域变量,但是在创建闭包时会获取这些变量的快照!subscribe
回调后,它仍使用与创建闭包时相同的变量进行操作。这是"stale closure"。那么,如何解决这个问题?
一种策略是在状态更改时通过将状态变量传递给useEffect
依赖项来取消订阅您的订阅回调并使用新的闭包重新订阅(但这将取决于Geolocation
API) 。有关其他选项,请参见上面的链接。
通过使用带有类方法的类组件来替换watch.subscribe
调用中的函数,您还可以轻松解决该问题。类方法没有纯函数式React钩子那样的过时的关闭问题。
我无法为您的问题提供具体的解决方案,因为设计更改可能会更改所需的行为,但是我希望这可以使您对问题有所了解。祝你好运!