Currently creating an application for a company. The user of the application is displayed on the map, and their pets are supposed to display on the map as well. In order to do that I need the boundaries of the map. I am using react-native-maps and it as a built function getMapBoundaries. When I use the function I have gotten the following errors
function getMapBoundaries does not exist
And the latest
Cannot set property map of undefined.
Here is what I have
const AppMapView = () => {
const handleRegionChange = async region => {
//I get an error for the statement below
console.log(
await this.map.getMapBoundaries()
.then(response => {
return response
})
)
};
handleRegionChange()
return (
<View style={styles.container}>
<MapView
ref={ref => {
this.map = ref;
}}
>
<Marker
coordinate={...}
>
<Image {...} />
</Marker>
</MapView>
</View>
)
};
export default AppMapView;
A code example would be much appreciated.
If anyone is still searching for the answer, this works:
<MapView
ref={mapView}
onRegionChangeComplete={async (val) => {
console.log(await mapRef.current.getMapBoundaries())
}
>
<Marker
coordinate={...}
>
</Marker>
</MapView>
You can get it from current of the ref
This code works for me:
mapRef = null;
onRegionChangeComplete = async () => {
console.log("onRegionChangeComplete", await this.mapRef.getMapBoundaries());
};
<MapView
ref={(ref) => {
this.mapRef = ref;
}}
onRegionChangeComplete={this.onRegionChangeComplete}
<Marker
coordinate={...}
>
</Marker>
</MapView>
Related
I'm trying to add and remove items from my movies favlist but I am unable to render things immediately with useState. I also trying to update favoritesFilm in UseEffect but my page crashed for continuing re-render.
This is my fav component:
export default function FavouriteBox() {
const navigation = useNavigation<NavigationProps>()
const [favoritesFilm, setFavorite] = useState<Movie[]>([])
const [isLoadingFav, setIsLoadingFav] = useState(true)
useEffect(() => {
getFav()
}, [])
useEffect(() => {
console.log(favoritesFilm)
}, [favoritesFilm])
async function removeMovie() {
const removed = StorageResources.storageRemove('favmovies')
setFavorite(favoritesFilm)
}
async function getFav() {
const favoriteMovies = await StorageResources.storageGet('favmovies')
setFavorite(favoriteMovies)
setIsLoadingFav(false)
}
const renderItemFav = ({ item }: any) => (
<FavMovie name={item.name} title={item.title} poster_path={item.poster_path} id={item.id} />
)
const FavMovie = ({ title, poster_path, name, id }: any) => (
<View style={styles.wrap}>
<Image
style={styles.image}
source={{
uri: `https://image.tmdb.org/t/p/w500/${poster_path}`,
}}
/>
{title && <Text style={styles.fav}>{title}</Text>}
{!title && <Text style={styles.fav}>{name}</Text>}
<MaterialCommunityIcons onPress={() => removeMovie()} name="bookmark-minus-outline" style={styles.book} />
</View>
)
return (
<View style={styles.container}>
<Text style={styles.title}>Preferiti</Text>
{isLoadingFav && <LoaderBox />}
{!isLoadingFav && (
<FlatList
data={favoritesFilm}
keyExtractor={(item) => item.id}
renderItem={renderItemFav}
horizontal
></FlatList>
)}
</View>
)
}
In my home component I use this function to add to fav:
const addToFavorites = async (item: Movie) => {
if (favorites.includes(item)) return null
StorageResources.storageSave('favmovies', [...favorites, item])
setFavorites([...favorites, item])
}
I would like to understand why it doesn't work and why every time I want to show movies in the favmovies component I have to refresh. (I used AsyncStorage for getItem and removeItem)
I am having trouble with the onPress handler in a marker component. onPress never seems to get called because it never calls onMarkerPress which prints out something to the console. Does anyone have this issue?
Here is my code:
const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);
{filteredMarkers.map((marker, index) => {
const scaleStyle={
transform: [
{
scale: interpolations[index].scale,
}
]
}
return (
<View style={styles.container}>
<MapView
ref={_map}
initialRegion={state.region}
provider={PROVIDER_GOOGLE}>
<Marker key={index} coordinate={marker.coordinate}>
<AnimatedTouchable style={[styles.markerWrap]} onPress={(e) => console.log(onMarkerPress(e))}>
<Animated.Image
source={require('../assets/map-marker.png')}
style={[styles.marker, scaleStyle]}
resizeMode="cover"
/>
</AnimatedTouchable>
</Marker>
</MapView>
</View>
);
})}
onMarkerPress:
const onMarkerPress = (mapEventData : any) => {
{console.log("PRESSED")}
const markerID = mapEventData._targetInst.return.key;
let x = (markerID * CARD_WIDTH) + (markerID * 20);
x = x - SPACING_FOR_CARD_INSET;
_scrollView.current.scrollTo({x: x, y: 0, animated: true});
}
I haven't been able to find anything to fix it. I'm using react-native maps
const finalMap = () => {
return(
<SafeAreaView style={styles.authContainerStyles}>
<MapView
style={styles.map}
provider={PROVIDER_GOOGLE}
region={{
latitude: !!userLocation ? userLocation.coords.latitude : 43.60271848664041,
longitude: !!userLocation
? userLocation.coords.longitude
: -116.20149258821509,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
}}
onMapReady = {this.map.getMapBoundaries()}
>
Try the below code or run this Snack here: https://snack.expo.io/Cu5qYmcZm
function Map() {
const [mapRef, updateMapRef] = useState(null);
const getBoundaries = () => {
if (mapRef === null) {
return;
}
mapRef
.getMapBoundaries()
.then((res) => {
console.log(res);
})
.catch((err) => console.log(err));
};
return (
<View>
<MapView
ref={(ref) => updateMapRef(ref)}
onMapReady={() => getBoundaries()}
/>
</View>
);
}
You need to store the ref to the map, so you can refer back to it later (when you check the boundaries). You could also store this in the state. Then after the map is ready, the event is fired and using the ref we can refer back to it and query the info about the boundaries.
I have a favorite button on the 'tweet' card that I show on the FeedScreen.js.
~~~~~~~~~ IMPORTS SNIP ~~~~~~~~~
function FeedScreen(props) {
const [feed, setFeed] = useState([]);
const [favorites, setFavorite] = useState([]);
const [refreshing, setRefreshing] = useState(false);
useEffect(() => {
loadFeed(0, 4);
}, []);
const loadFeed = async (last_id = 0, limit = 1) => {
setRefreshing(true);
const response = await tweetsApi.getTweets(last_id, limit);
if (response.ok) {
setFeed(response.data["data"].concat(feed));
} else {
console.log(response.problem);
}
setRefreshing(false);
};
const handleBookmark = async (item_id) => {
const response = await tweetsApi.toggleBookmark(item_id);
if (response.ok) {
console.log("ok response");
setFavorite(favorites.concat(item_id));
// I've tried this as well
// setFavorite([...favorites].concat(item_id));
// but in vain
console.log(favorites);
}
};
return (
<Screen style={styles.screen}>
<FlatList
data={feed}
keyExtractor={(tweet) => {
return tweet.id.toString();
}}
renderItem={({ item }) => (
~~~~~~~~~ SNIP ~~~~~~~~~
<CardFooter
style={{ marginLeft: 20 }}
item={item}
onPress={handleBookmark}
/>
</View>
)}
ItemSeparatorComponent={ListItemSeparator}
refreshing={refreshing}
onRefresh={() => {
loadFeed(feed[0]["id"], 2);
}}
/>
</Screen>
);
}
~~~~~~~~~ SNIP ~~~~~~~~~
And here's the CardFooter.js :
~~~~~~~~~ SNIP ~~~~~~~~~
function CardFooter({ item, onPress }) {
return (
<View style={styles.bookmark}>
<TouchableOpacity
onPress={() => {
return onPress(item.id);
}}
>
{item.bookmarked && (
<FontAwesome name="bookmark" size={24} color="red" />
)}
{!item.bookmarked && (
<FontAwesome5 name="bookmark" size={24} color="black" />
)}
</TouchableOpacity>
</View>
</View>
);
}
export default CardFooter;
~~~~~~~~~ SNIP ~~~~~~~~~
However the component doesn't seem to re render.
I've looked at these :
react-component-not-re-rendering-after-using-usestate-hook
Similar here
Another one 17 days back - why-usestate-is-not-re-rendering
usestate-not-re-rendering-when-updating-nested-object
All of these and similar other ones, each one of them point to the fact that the a new array should be created so that react re-renders it.
Update
console.log output
yes the console.log is printing the array, although one value previous. That's because useState is async so it isn't printing the realtime array. So, when the second time this is called, it would show one item_id ( the previous one ) added to favorites
I finally solved this by managing the state in the component itself.
Not sure if this is 'the proper way' to do this, but read here (how-to-add-a-simple-toggle-function-in-react-native) that this is how you can do this.
So, now the bookmark component gets its response from the top level component ( FeedScreen.js ) :
const handleBookmark = async (item_id) => {
const response = await tweetsApi.toggleBookmark(item_id);
if (response.ok) {
return true;
} else {
return false;
}
};
And changing the CardFooter.js i.e. where the bookmark component resides.
function CardFooter({ item, onPress }) {
const [favorite, setFavorite] = useState(item.bookmarked);
return (
<View style={styles.bookmark}>
<TouchableOpacity
onPress={async () => {
let response = await onPress(item.id);
if (response) {
setFavorite(!favorite);
} else {
alert("Some error occurred");
}
}}
>
{favorite && <FontAwesome name="bookmark" size={24} color="red" />}
{!favorite && (
<FontAwesome5 name="bookmark" size={24} color="black" />
)}
</TouchableOpacity>
</View>
</View>
);
}
Concerns
I am a bit concerned about handling the response in this component.
Should I handle the async operation in the bottom component ?
I am using react native maps for displaying a map in my application, and this map should display markers that are fetched from a database online. When the map is mounted, and after fetching the marker data location points, I am updating a state containing the array of marker points, however, the markers do not get rendered after setting the state. Is there any work around in this? Here's a sample code:
P.S. This only occurs in iOS.
const [markerPoints, setMarkerPoints] = useState([])
useEffect(() => {
getMarkerPoints()
}, [])
const getMarkerPoints = callback => {
axios
.get(
'some end point',
)
.then(res => {
if (res.status === 200) {
setMarkerPoints(res.data.results)
}
})
.catch(error => {
console.log(error)
})
}
const renderMarkers = () => {
return markerPoints.map((place, index) => {
return (
<Marker
key={index}
coordinate={{
latitude: place.geometry.location.lat,
longitude: place.geometry.location.lng,
}}
/>
)
}
}
return (
<MapView
ref={map}
provider={PROVIDER_GOOGLE}
style={styles.map}
region={curRegion}
showsUserLocation={true}
showsMyLocationButton={false}
onRegionChangeComplete={onMapRegionChangeComplete}
customMapStyle={mapStyles}
>
{renderMarkers()}
</MapView>
)