React useEffect 避免在每次更新时更新回调
React useEffect avoid update callback in every update
有没有办法避免在 useEffect 中更新回调?。例如,我用 geofire 订阅了一个事件,它监听变化并接收位置。
我需要更新我的状态,而不是每次更新都订阅。
当前行为
- 已订阅 geofire 并接收位置 (A)
- 使用新位置 (A) 更新我的状态
- 再次订阅 geofire 并接收位置 (A)
这是一个无限循环。我无法收到其他位置
预期行为
- 仅订阅一次 geofire 并接收位置 (A,B,C)
- 使用新位置(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;
您是否检查过 return 条件是否在页面加载时起作用(只需将控制台日志放在那里)?
从阅读来看,似乎两个 useEffects 都在页面加载时被调用,但第二个应该立即退出,然后在第一个完成后再次调用。
然后我注意到你通过异步回调更新状态,这可能与它有关。不亲眼所见很难说。
我会说尝试用函数而不是对象重写 setCurrentLocation:
setCurrentLocation((currentLocation) => ({
...currentLocation,
[key]: {location},
}));
也许它没有通过并在新旧数据之间切换。
有没有办法避免在 useEffect 中更新回调?。例如,我用 geofire 订阅了一个事件,它监听变化并接收位置。
我需要更新我的状态,而不是每次更新都订阅。
当前行为
- 已订阅 geofire 并接收位置 (A)
- 使用新位置 (A) 更新我的状态
- 再次订阅 geofire 并接收位置 (A)
这是一个无限循环。我无法收到其他位置
预期行为
- 仅订阅一次 geofire 并接收位置 (A,B,C)
- 使用新位置(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;
您是否检查过 return 条件是否在页面加载时起作用(只需将控制台日志放在那里)?
从阅读来看,似乎两个 useEffects 都在页面加载时被调用,但第二个应该立即退出,然后在第一个完成后再次调用。
然后我注意到你通过异步回调更新状态,这可能与它有关。不亲眼所见很难说。
我会说尝试用函数而不是对象重写 setCurrentLocation:
setCurrentLocation((currentLocation) => ({
...currentLocation,
[key]: {location},
}));
也许它没有通过并在新旧数据之间切换。