I would like show image on my markers, but it works only when I use the icon attribute of the marker. I need to use the subview to manage the style. When I use the ICON attribute, the view image appear (so I have two image on the map) but not showing when it's in comment.
This how I fetch the data and update the state.
componentDidMount(){
getmarkers().then(data => {
let test = []
data.forEach(element => {
test.push(
{
latlng:
{
latitude: JSON.parse(element.latitude),
longitude: JSON.parse(element.longitude)
},
name: JSON.parse(element.images)[0],
id: element.id,
image: JSON.parse(element.images)[0]
}
)
});
this.setState({ markers: test, loaded: true })
})
}
}
This is my view
{this.state.markers.map((marker, i) => (
<Marker
key={i}
coordinate={marker.latlng}
title={marker.name}
description={marker.name}
tracksViewChanges={false}
// icon={{ uri: 'https://www.testeed.com/uploads/minifiedplaces/' + marker.image}}
>
<View>
<Image source={{ uri: 'https://www.testeed.com/uploads/minifiedplaces/' + marker.image }} style={{ width: 40, height: 40, borderRadius: 6 }} />
</View>
</Marker>
))}
The issue come from Trackviewchange. If you put this value to false. the application is lagging. then if you put the value to false, the application do not load the image at first loading.
So you have to init Trackviewchange to True and create promise after the execution of your fetch/foreach, if it doesn't work, you can do a a setimeout or setinterval to change the value of trackviewchange to false to show images changes and get a better smooth user experience.
const customMarkerImage = require("../../../customMarkerImage.png");
<MapView.Marker>
<View >
<Image source={customMarkerImage} onLoad={() => this.forceUpdate()}>
</Image>
</View>
</MapView.Marker>
It is probably about this issue : https://github.com/react-native-community/react-native-maps/issues/924
Related
`
export default function ChipsTest({ }) {
const interests = [{ name: 'ABC', selected: false, id:1, }, { name: 'XYZ', selected: false, id:2 }, { name: 'Bla bla', selected: false, id: 3 } ];
return ( <View style={styles.container}> {interests.map((interest, index) => ( <TouchableOpacity> <Chip onPress={() => { interest.selected = !interest.selected; interest.name = 'Ali'; console.log(interests);
}}
key={interest.id}
selected={ interest.selected}
> {interest.name} </Chip>
</TouchableOpacity>
))}
</View>
);
`
Hi, I am using react native chips on select I am updating value of selected item but its not reflecting in UI/View. I am able to see value updated in variable/ console. Can anyone help?
I would try to use useState hook to solve your problem.
Basically, React native will re-render your screen's UI if the state changes.
More here: https://felixgerschau.com/react-rerender-components/
Also, I'm not sure what <Chip/> component is. I would move onPress event listener to <TouchableOpacity onPress={...}> OR keep it in <Chip> and remove <TouchableOpacity>.
And then, I would wrap {interest.name} within <Text> {interest.name} </Text>
Good luck!
I am using react native deck swipper to display arrays of data.
//ARRAYS OF DATA
const docs = shuffleArray([
{
title: "Austin Wade",
content: 22,
featured_image: require("../../assets/images/beach.jpeg"),
created_at: "2020-11-11T16:26:13.000000Z",
news_url: "https://www.google.com",
key: "caseex6qfO4TPMYyhorner",
},..... more json arrays...])
My problem is, i want to be able to extract the news_url when the card is swipped left, and also use the extracted URL to open expo inapp-browser that will display the webpage e.g www.google.com
I have written a function that opens a web browser.
PLEASE CAN SOMEONE HELP ME
//SWIPPER
<SafeAreaView style={{ flex: 1 }}>
{/* <View style={{ flex: 1, padding: 16 }}> */}
<Swiper
ref={useSwiper}
cards={docs}
cardIndex={0}
backgroundColor="transparent"
stackSize={2}
showSecondCard
cardHorizontalMargin={0}
animateCardOpacity
disableBottomSwipe
renderCard={
((card) => <Cardz card={card} />)
}
onSwiped={(cardIndex) => {
console.log(cardIndex);
}}
onSwipedAll={() => {
console.log("onSwipedAll");
}}
onSwipedTop={() => {
console.log(getLatestNews);
}}
onSwipedBottom={() => {
// <Toast message={success} onDismiss={() => {}} />
}}
//swipping left, opens expo web browser
onSwipedLeft={() => {
_handleWebBrowserAsync(getNewsUrl);
//Alert.alert();
}}
></Swiper>
{/* </View> */}
</SafeAreaView>
);
//WEB BROSWER
//async function to open app inapp web browser
const _handleWebBrowserAsync = async (url) => {
try {
_addLinkingListener();
await WebBrowser.openBrowserAsync(url);
//only calls this method in IOS Devices as it only
//works for IOS Devices
if (Constants.platform.ios) {
_removeLinkingListener();
}
} catch (error) {
Alert.alert("Error:", error.message);;
console.log("Error:" + error.message);
}
};
//CARD COMPONENT
import React from 'react'
import { View, Text, Image, ImageSourcePropType } from 'react-native'
import styles from './Card.styles'
const Cardz = ({ card }) => (
<View activeOpacity={1} style={styles.card}>
<Image
style={styles.image}
source={card.featured_image}
resizeMode="cover"
/>
<View style={styles.photoDescriptionContainer}>
<Text style={styles.text}>{`${card.title}, ${card.content}`}</Text>
</View>
</View>
);
export default Cardz
There are event callbacks.
For example: There is onSwiped prop which is a
function to be called when a card is swiped. it receives the swiped card index.
So, you'll get that index value which you'll use to get the object from the docs array. If the swiped index is 2, you can get the object like this: docs[2].
I have custom markers being rendered to my map and do so exactly as I want. I'm using Custom Marker which is a View, Image, and then text specific to an event over the image.
For some reason using a custom marker view is blocking the onPress on the Marker component.
I've tested the onPress event as similiar to below for testing:
<Marker onPress={() => {console.log('Pressed')}}> ... but only logs the press message when I remove my custom marker view inside the Marker component.
Is there a reason why the custom marker view would be stopping the onPress? How do I get around this and fire an onPress event for a custom marker?
Added full code below for better look. Right now it is working but only because I am using the onSelect event for iOS. The onPress works the way it is for Android but not iOS.
<MapView
style={styles.map}
ref={ map => {this.map = map }}
region={this.state.region}
onRegionChangeComplete={this.onRegionChange}
rotateEnabled={false}
loadingEnabled={true}
>
{matches.map((marker, index) => {
return (
<MapMarker
key={index}
mapMarker={marker}
handlePress={() => {
this.map.animateToRegion({
latitude: marker.location.latlng.latitude,
longitude: marker.location.latlng.longitude
}, 100)
}}
/>
)
})}
</MapView>
MapMarker.js
render() {
const { mapMarker } = this.props;
return (
<Marker
ref={(ref) => {this.markerRef = ref; }}
coordinate={mapMarker.location.latlng}
title={mapMarker.location.streetName}
stopPropagation={true}
pointerEvents='auto'
onPress={() => console.log('pressed')}
onSelect={() => {
this.props.handlePress();
}}
>
<CustomMapMarker
gameType={mapMarker.matchType}
isSanctioned={mapMarker.isSanctioned}
startDate={mapMarker.startAt}
/>
<Callout style={styles.customCallout}>
<CustomMarkerCallout markerInfo={mapMarker} />
</Callout>
</Marker>
);
}
Fixed the issue by adding onSelect which is iOS specific. The onPress was only working for Android so don't know if this is the right answer but is working for me as of now.
I have the map working when it loads, but whenever I pass props the map itself never changes.
The marker changes, but is always 1 state behind what it should be, obviously a sync issue but I'm not sure how to fix this in my component.
class Map extends React.Component {
state = {
center: { lat: 50.937531, lng: 6.960278600000038 }
}
componentWillReceiveProps = () => {
this.setState({
center: {
lat: Number(parseFloat(this.props.city.lat)),
lng: Number(parseFloat(this.props.city.lng))
}
});
}
render() {
console.log(this.state.center)
return (
<div>
<MapDetails
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyB-L-IikkM6BZ_3Z2QIzbkx4pdAkP76tok&v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100vh`}} />}
mapElement={<div style={{ height: `100%` }} />}
mapCenter={this.state.center}
/>
</div>
)
}
}
const mapStateToProps = (state) => {
return { city: state.CityNameReducer }
}
export default connect(mapStateToProps)(Map);
const MapDetails = withScriptjs(withGoogleMap(props =>
<GoogleMap
defaultZoom={12}
defaultCenter={props.mapCenter}
>
<Marker
position={props.mapCenter}
/>
</GoogleMap>
));
The biggest question I have is why the map itself is not updating?
Add a key to GoogleMap component. a Key should be unique each time provided. for your testing use new Date().getTime() function.
<GoogleMap key={new Date().getTime()}/>
as I mentioned its for only testing so make sure to provide this key in better way
I may recommend you to use shouldComponentUpdate(nextProps, nextState) {} instead of componentWillReceiveProps().
I recommend you to read the following page, to understand how it works.
Updating and componentWillReceiveProps
I don't have more information about what is happening in the parent of your component, so I cannot go deeper to the problem. But I think you can get the solution by changing that.
I have a map react component and I'm dynamically adding markers.The problem is that when I add markers in the store, the whole map rerenders instead of just appending the markers to the map. Has anyone got any suggestions on how this could be fixed?? I'm pretty sure that I need to Inject the store into CPMap function exclusively, I'm just not sure how.
const CPMap = withGoogleMap((props) => (
<GoogleMap
ref={props.onMapLoad}
style={{
height: 100,
width: 100,
}}
onCenterChanged={props.boundsChanged}
defaultOptions={{ styles: this.mapStyles }}
defaultZoom={props.zoom}
defaultCenter={{ lat: props.center.lat, lng: props.center.lng }}>
<MarkerClusterer
gridSize={40}>
{
props.markers.map(({ key, position }) => (
<Marker
key={key}
position={{ lat: position.lat, lng: position.lng }}
icon={{
url: require('../../images/marker.png')
}}
/>
))
}
</MarkerClusterer>
</GoogleMap >
))
return (
<CPMap
style={{
height: 100,
width: 100,
}}
onMapLoad={(gMap) => {
map = gMap
this.props.map.fetchMarkers()
}}
boundsChanged={() => {
this.props.map.fetchMarkers()
}}
center={this.props.map.center}
zoom={this.props.map.zoom}
markers={mobx.toJS(this.props.map.markers)}
containerElement={
<div style={{ height: 'calc(100vh - 70px)' }
} />
}
mapElement={
<div style={{ height: 'calc(100vh - 70px)' }} />
} />
)
}
I'd propose you the following solution: don't pass makers directly to CMap component, but use store instead;
const markersStore = observable({
markers: []
});
Then in your component - move MarkersClusterer to the separate component and pass markersStore one level deeper:
//import markersStore or inject via mobx-react package
class MyComponent extends Component {
render() {
const CMap = withGoogleMap((props) => (
<GoogleMap
...
<Clusterer markersStore={props.markersStore} />
/>
))
return (
<CMap
...
markersStore={markersStore}
/>
)
}
}
Make your new Cluster component observable so it updates when markersStore "markers" property updates;
#observable
class Clusterer extends Component {
render(){
const { markers } = this.props.markersStore;
return (
<MarkerClusterer>
{ markers.map(...)}
</MarkerClusterer>
)
}
}
The final change is to update your fetchMarkers method so it populates the markersStore with new data.
With this solution CMap component doesn't know anything about markers and it doesn't updates when new data received. At the same time MarkersClusterer component becomes more clever and "observes" changes in the markersStore.