React Native Maps 标注渲染
React Native Maps Callout Rendering
我正在使用 react-native-maps
来显示我所在地区的火车站标记。每个标记都有一个带有接近列车实时数据的标注。
问题是;我在地图上的每个标记的每个标注都在背景中呈现。此外,由于我有来自实时的新数据 API,因此每个标注都将重新呈现。这导致呈现数百个视图,即使我只需要按下标记的标注。app screenshot
有没有办法确保在用户按下特定标记之前不会呈现标注?新闻发布后;我还想确保只渲染和显示特定标记的标注。
我的代码:
地图屏幕:
const MapScreen = props => {
// get user location from Redux store
// this is used to center the map
const { latitude, longitude } = useSelector(state => state.location.coords)
// The MapView and Markers are static
// We only need to update Marker callouts after fetching data
return(
<SafeAreaView style={{flex: 1}}>
<MapView
style={{flex: 1}}
initialRegion={{
latitude: parseFloat(latitude) || 37.792874,
longitude: parseFloat(longitude) || -122.39703,
latitudeDelta: 0.06,
longitudeDelta: 0.06
}}
provider={"google"}
>
<Markers />
</MapView>
</SafeAreaView>
)
}
export default MapScreen
标记组件:
const Markers = props => {
const stationData = useSelector(state => state.stationData)
return stationData.map((station, index) => {
return (
<MapView.Marker
key={index}
coordinate={{
// receives station latitude and longitude from stationDetails.js
latitude: parseFloat(stationDetails[station.abbr].gtfs_latitude),
longitude: parseFloat(stationDetails[station.abbr].gtfs_longitude)
}}
image={stationLogo}
zIndex={100}
tracksInfoWindowChanges={true}
>
<MapView.Callout
key={index}
tooltip={true}
style={{ backgroundColor: "#ffffff" }}
>
<View style={styles.calloutHeader}>
<Text style={{ fontWeight: "bold" }}>{station.name}</Text>
</View>
<View style={styles.calloutContent}>
<StationCallout key={index} station={stationData[index]} />
</View>
</MapView.Callout>
</MapView.Marker>
);
});
};
StationCallout 组件:
const StationCallout = (props) => {
return(
props.station.etd.map((route, index) => {
const approachingTrains = function() {
trainText = `${route.destination} in`;
route.estimate.map((train, index) => {
if (index === 0) {
if (train.minutes === "Leaving") {
trainText += ` 0`;
} else {
trainText += ` ${train.minutes}`;
}
} else {
if (train.minutes === "Leaving") {
trainText += `, 0`;
} else {
trainText += `, ${train.minutes}`;
}
}
});
trainText += " mins";
return <Text>{trainText}</Text>;
};
return <View key={index}>
{approachingTrains()}
</View>;
})
)
};
export default StationCallout
在 ComponentDidMount 上,您应该获取所有列车的数据,以便可以在其位置上设置所有标记。您可以使用 firebase 的 once('value') 事件执行此操作,此事件仅在被调用时从引用中获取数据一次,因此您将在组件挂载时调用它。
现在所有指针都在它们的位置上,用户可以单击任何一个指针来跟踪它的运动对吗?
所以每个指针都必须有一些独特的东西,比如火车 ID 或我不知道你的数据库结构的东西,所以我假设你有火车 ID,
现在在标记的 onPress 函数中,你应该传递这个 TrainID。
示例:
onPress={()=> this.TrackSpecificTrain(trainID) }
现在在 TrackSpecificTrain
函数中,您应该使用列车 ID 和 firebase on('value') 事件调用您的数据库引用,现在您将继续获取所选列车的实时数据,并且您可以更新本地使用来自 firebase 的新数据状态 stationData
。
例子
TrackSpecificTrain=(trainID)=>{
const ref = database().ref(`YourTrainsRef/${trainID}/`)
ref.on('value',( snapshot)=>{
//Update your local state with new data in snapshot
})
}
RemoveTracker=(trainID)=>{
const ref = database().ref(`YourTrainsRef/${trainID}/`)
ref.off("value")
}
现在我们还使用 RemoveTracker
,因为如果用户单击另一个标记,您可能需要停止跟踪之前的火车,这样它将开始跟踪新标记上的 trainID 并停止跟踪之前的火车!。
其实我自己找到了答案。我已经创建了对每个标记的引用,然后将 onPress 属性 传递给 并将 showCallout 属性 传递给它的 Callout 组件。
标记组件:
export default function Markers() {
const {
stations: { station }
} = require("../../bartData/stations");
const [clickedMarkerRef, setClickedMarkerRef] = useState(null)
return station.map((trainStation, index) => {
return (
<MapView.Marker
key={trainStation.abbr}
coordinate={{
latitude: parseFloat(trainStation.gtfs_latitude),
longitude: parseFloat(trainStation.gtfs_longitude)
}}
image={Platform.OS === "ios" ? station_ios : station_android}
zIndex={100}
tracksInfoWindowChanges={true}
onPress={() => setClickedMarkerRef(index)}
>
<CalloutContainer
key={trainStation.abbr}
stationName={trainStation.name}
stationAbbr={trainStation.abbr}
showCallOut={clickedMarkerRef === index}
/>
</MapView.Marker>
);
});
}
并且Callout组件只有在showCallOut为true时才会获取数据。
在标注组件中
useEffect(() => {
if (props.showCallOut === true) {
fetchTrainDepartures();
const intervalId = setInterval(fetchTrainDepartures, 10000);
return () => clearInterval(intervalId);
}
}, []);
因此,除非您单击标记,否则本地状态将保持为空,并且标注不会获取任何数据。
当您点击索引 0 处的标记时:
- clickedMarkerRef 现在为 0。
- showCallout 为真 => {clickMarkerRef === index}
- 关于 Callout.js 文件下的 useEffect hook => props.showCallout 为真。
- 仅为此标注获取数据。
我正在使用 react-native-maps
来显示我所在地区的火车站标记。每个标记都有一个带有接近列车实时数据的标注。
问题是;我在地图上的每个标记的每个标注都在背景中呈现。此外,由于我有来自实时的新数据 API,因此每个标注都将重新呈现。这导致呈现数百个视图,即使我只需要按下标记的标注。app screenshot
有没有办法确保在用户按下特定标记之前不会呈现标注?新闻发布后;我还想确保只渲染和显示特定标记的标注。
我的代码:
地图屏幕:
const MapScreen = props => {
// get user location from Redux store
// this is used to center the map
const { latitude, longitude } = useSelector(state => state.location.coords)
// The MapView and Markers are static
// We only need to update Marker callouts after fetching data
return(
<SafeAreaView style={{flex: 1}}>
<MapView
style={{flex: 1}}
initialRegion={{
latitude: parseFloat(latitude) || 37.792874,
longitude: parseFloat(longitude) || -122.39703,
latitudeDelta: 0.06,
longitudeDelta: 0.06
}}
provider={"google"}
>
<Markers />
</MapView>
</SafeAreaView>
)
}
export default MapScreen
标记组件:
const Markers = props => {
const stationData = useSelector(state => state.stationData)
return stationData.map((station, index) => {
return (
<MapView.Marker
key={index}
coordinate={{
// receives station latitude and longitude from stationDetails.js
latitude: parseFloat(stationDetails[station.abbr].gtfs_latitude),
longitude: parseFloat(stationDetails[station.abbr].gtfs_longitude)
}}
image={stationLogo}
zIndex={100}
tracksInfoWindowChanges={true}
>
<MapView.Callout
key={index}
tooltip={true}
style={{ backgroundColor: "#ffffff" }}
>
<View style={styles.calloutHeader}>
<Text style={{ fontWeight: "bold" }}>{station.name}</Text>
</View>
<View style={styles.calloutContent}>
<StationCallout key={index} station={stationData[index]} />
</View>
</MapView.Callout>
</MapView.Marker>
);
});
};
StationCallout 组件:
const StationCallout = (props) => {
return(
props.station.etd.map((route, index) => {
const approachingTrains = function() {
trainText = `${route.destination} in`;
route.estimate.map((train, index) => {
if (index === 0) {
if (train.minutes === "Leaving") {
trainText += ` 0`;
} else {
trainText += ` ${train.minutes}`;
}
} else {
if (train.minutes === "Leaving") {
trainText += `, 0`;
} else {
trainText += `, ${train.minutes}`;
}
}
});
trainText += " mins";
return <Text>{trainText}</Text>;
};
return <View key={index}>
{approachingTrains()}
</View>;
})
)
};
export default StationCallout
在 ComponentDidMount 上,您应该获取所有列车的数据,以便可以在其位置上设置所有标记。您可以使用 firebase 的 once('value') 事件执行此操作,此事件仅在被调用时从引用中获取数据一次,因此您将在组件挂载时调用它。
现在所有指针都在它们的位置上,用户可以单击任何一个指针来跟踪它的运动对吗?
所以每个指针都必须有一些独特的东西,比如火车 ID 或我不知道你的数据库结构的东西,所以我假设你有火车 ID, 现在在标记的 onPress 函数中,你应该传递这个 TrainID。
示例:
onPress={()=> this.TrackSpecificTrain(trainID) }
现在在 TrackSpecificTrain
函数中,您应该使用列车 ID 和 firebase on('value') 事件调用您的数据库引用,现在您将继续获取所选列车的实时数据,并且您可以更新本地使用来自 firebase 的新数据状态 stationData
。
例子
TrackSpecificTrain=(trainID)=>{
const ref = database().ref(`YourTrainsRef/${trainID}/`)
ref.on('value',( snapshot)=>{
//Update your local state with new data in snapshot
})
}
RemoveTracker=(trainID)=>{
const ref = database().ref(`YourTrainsRef/${trainID}/`)
ref.off("value")
}
现在我们还使用 RemoveTracker
,因为如果用户单击另一个标记,您可能需要停止跟踪之前的火车,这样它将开始跟踪新标记上的 trainID 并停止跟踪之前的火车!。
其实我自己找到了答案。我已经创建了对每个标记的引用,然后将 onPress 属性 传递给
标记组件:
export default function Markers() {
const {
stations: { station }
} = require("../../bartData/stations");
const [clickedMarkerRef, setClickedMarkerRef] = useState(null)
return station.map((trainStation, index) => {
return (
<MapView.Marker
key={trainStation.abbr}
coordinate={{
latitude: parseFloat(trainStation.gtfs_latitude),
longitude: parseFloat(trainStation.gtfs_longitude)
}}
image={Platform.OS === "ios" ? station_ios : station_android}
zIndex={100}
tracksInfoWindowChanges={true}
onPress={() => setClickedMarkerRef(index)}
>
<CalloutContainer
key={trainStation.abbr}
stationName={trainStation.name}
stationAbbr={trainStation.abbr}
showCallOut={clickedMarkerRef === index}
/>
</MapView.Marker>
);
});
}
并且Callout组件只有在showCallOut为true时才会获取数据。 在标注组件中
useEffect(() => {
if (props.showCallOut === true) {
fetchTrainDepartures();
const intervalId = setInterval(fetchTrainDepartures, 10000);
return () => clearInterval(intervalId);
}
}, []);
因此,除非您单击标记,否则本地状态将保持为空,并且标注不会获取任何数据。
当您点击索引 0 处的标记时:
- clickedMarkerRef 现在为 0。
- showCallout 为真 => {clickMarkerRef === index}
- 关于 Callout.js 文件下的 useEffect hook => props.showCallout 为真。
- 仅为此标注获取数据。