Will Google API trigger multiple times when updating current location? - react-native

UPDATED
Found out more information about this question on the github page from the library I use.
Answer:
When using the library react-native-maps-directions the google API only gets triggered when the origin, destination or waypoint updates. Since then there is a new calculation needed.
Question:
So I have this question because I currently am using the Google Directions API which uses the "pay-as-you-go model". Now I am scared to use the API in my code that when the user location updates it will triggers the API again so it will think I want a new result from the Directions API.
I'm using the react-native-maps-directions library to show the route on the map.
There is just more clarification needed for me.
Does the API only get called once when opening the component or will
it also trigger during the update of the user location even I don't
want to do something with the user location in the query?
Here is a part of my code that shows the current flow I'm talking about:
The API Key gets registered in the constructor
constructor(props){
super(props);
if (props.apiKey !== undefined) {
this.apiKey = props.apiKey;
}
this.origin = { latitude: this.route.waypoints[0].latitude, longitude:
this.route.waypoints[0].longitude };
this.destination = { latitude: this.route.waypoints[this.route.waypoints.length - 1].latitude, longitude: this.route.waypoints[this.route.waypoints.length - 1].longitude };
this.GOOGLE_MAPS_APIKEY = this.apiKey;
}
The getUserLocation get called in componentWillUnmount (It is the only thing that has to update and I don't want to make this to trigger the API)
getUserLocation = async () => {
this.location = await Location.watchPositionAsync(
{
enableHighAccuracy: true,
distanceInterval: 1,
timeInterval: 100,
},
(newLocation) => {
let coords = newLocation.coords;
console.log("USER LOCATION", coords);
this.setState({
userLocation: coords,
region: {
LATITUDE: coords.latitude,
LONGITUDE: coords.longitude
}
});
},
(error) => console.log(error)
);
};
I use the API Key in the render, not where the marker of the user get updated
<MapViewDirections
origin={this.origin}
waypoints={this.coordinates.slice(1, -1)}
destination={this.destination}
apikey={this.GOOGLE_MAPS_APIKEY}
strokeWidth={20}
strokeColor="#DD8526"
/>
This is the marker that gets updated, it's in the same MapView as the block above
<Marker style={styles.markerStyle} coordinate={{ latitude: lat, longitude: lng }} title="Your Location">
<Text style={styles.markerTextStyle}>You</Text>
<Image source={require("./../../assets/img/other/you.png")} style={{ height: 20, width: 20 }/>
</Marker>
There is only one Component in the render that updates so I don't know if this will actually trigger the API call again.
Feel free to say it when you need anything to be more specified to bring the right information about this!

Related

Message Feed not Updating when Next Texts are Sent React Native

I have a pretty simple messaging component, all of the mutations and queries involved work properly. If I send a message, the mutation fires, and then the updated conversation is pulled from a query and changes the local state value of currentChat to the newest version of that chat. The query works, as shown by console.log statements, but the screen does not re-render or update at all. If I leave the page and come back to it, it is now updated. Similarly, if I hit ctrl-s in my IDE, the page refreshed and the expected messages were displayed. I use useEffects to mark a change in currentChatroom and all of the rendering functions are based off of values in that state, so I am unsure why it is not updating the visuals when the data has been updated
EDIT: Adding some code for clarity, the functions are all pretty huge (mostly styling logic) so I'm gonna show the barebones of it.
const [msgs, setMsgs] = useRecoilState(messageDataState)
// RENDERINGS //
// Renders the Next Upcoming Meetings
function renderUpcomingMeetings(){
if (msgs.length < 1){ // no meetings
return(
<View style={Styles.upcomingView}>
<Text style={{...FONTS.Title, color: COLORS.iconLight, textAlign: 'center', margin: 10}}>
You have no messages yet!
</Text>
</View>
)
}
return(
<ScrollView style={{...Styles.upcomingView, maxHeight: 350}}>
{renderMsgs()}
</ScrollView>
)
}
// Renders each meeting card
function renderMsgs(){
return msgs.filter(msg => {
if (!msg.sent && msg.deleted){
return null
}
}).map(meeting => {
let dt = convertDateTimeToJavaScript(msg.sentTime)
return(
// A bunch of irrelevant styling stuff
)
})
}
// SENDINGS //
// Sends message
async function handleAssignSubmissionClick(){
setLoading(true)
sendMessage({client: client, sDate: sDate})
.then((resolved) => {
setRefresh(!refresh)
})
}
// Triggers the Requery when refresh is changed post mutation
useEffect(() => {
getAndSetUser()
setLoading(false)
}, [refresh])
// Gets the user obj and resets the userState
async function getAndSetUser(){
await client.query({
query: GET_CHAT,
fetchPolicy: 'network-only'
})
.then(async (resolved) => {
await setMsgs(resolved.data.getChat.messages)
})
.catch((error) => {
console.log(error)
})
}

Do I need Pagination, Lazy Loading or none in my React-Native app?

I am implementing an app in React-Native where I am fetching "restaurants" as documents from Cloud-Firestore and I am also using onSnapshot() listener. When the app is ready for launch, there will probably be around max 3000 restaurants. I have a few questions to ask around this matter.
-Do I need to implement Pagination/Lazy Loading for a better UX and less cost OR 3000 is not a big number so it won't affect the performance that much?!
-If I do need to implement one of them, which one should I implement?
-If I dont need, then is there a way to compress the JSON data when fetching in React-Native so it saves space? And then decompress when requested by the user.
Can user search for a restaurant while lazy loading is implemented?
EDIT:
I managed to implement lazy-loading and its working perfectly, however, using snapshot() listener will make lazy-loading pointless but I must use it because I need to fetch on real-time new "restaurants" or "orders. So, what else can I use instead of snapshot()? Or maybe is there a way to still use snapshot() but with a small change to the code?
Second question: after the above problem is solved, am I able to implement the search for a restaurant? It seems quite tricky knowing that I am using lazy-loading.
componentDidMount() {
try {
// Cloud Firestore: Initial Query
this.retrieveData();
}
catch (error) {
console.log(error);
}
};
retrieveData = () => {
try {
this.setState({
loading: true
})
var initialQuery = firebase.firestore().collection('restaurants')
.orderBy('res_id')
.limit(this.state.limit)
//let documentSnapshots = await initialQuery.get();
initialQuery.onSnapshot((documentSnapshots => {
var All = documentSnapshots.docs.map(document => document.data());
var lastVisible = All[All.length - 1].res_id;
this.setState({
All: All,
lastVisible: lastVisible,
loading: false,
});
}));
}
catch (error) {
console.log(error);
}
};
retrieveMore = async () => {
try {
// Set State: Refreshing
this.setState({
refreshing: true,
});
// Cloud Firestore: Query (Additional Query)
var additionalQuery = await firebase.firestore().collection('restaurants')
.orderBy('res_id')
.startAfter(this.state.lastVisible)
.limit(this.state.limit)
// Cloud Firestore: Query Snapshot
var documentSnapshots = await additionalQuery.get();
// Cloud Firestore: Document Data
var All = documentSnapshots.docs.map(document => document.data());
// Cloud Firestore: Last Visible Document (Document ID To Start From For Proceeding Queries)
var lastVisible = All[All.length - 1].res_id;
// Set State
this.setState({
All: [...this.state.All, ...All],
lastVisible: lastVisible,
refreshing: false,
});
console.log('Retrieving additional Data', this.state.All);
}
catch (error) {
console.log(error);
}
};
// Render Header
renderHeader = () => {
try {
return (
<Text style={styles.headerText}>Items</Text>
)
}
catch (error) {
console.log(error);
}
};
// Render Footer
renderFooter = () => {
try {
// Check If Loading
if (this.state.loading) {
return (
<ActivityIndicator />
)
}
else {
return null;
}
}
catch (error) {
console.log(error);
}
};
render() {
return (
<SafeAreaView style={styles.container}>
<FlatList
// Data
data={this.state.All}
// Render Items
renderItem={({ item }) => (
<View style={styles.itemContainer}>
<Text>(ID: {item.res_id}) {item.rest_name} {item.rest_location}</Text>
</View>
)}
// Item Key
keyExtractor={(item, index) => String(index)}
// Header (Title)
ListHeaderComponent={this.renderHeader}
// Footer (Activity Indicator)
ListFooterComponent={this.renderFooter}
// On End Reached (Takes a function)
onEndReached={this.retrieveMore}
// How Close To The End Of List Until Next Data Request Is Made
onEndReachedThreshold={0.1}
// Refreshing (Set To True When End Reached)
refreshing={this.state.refreshing}
/>
</SafeAreaView>
)
}
Pagination and Lazy Loading are kind of the same thing in this case. You will be either switching pages or infinitely scrolling while fetching new data until there is no more data to fetch. In either case, you need it. Look here https://firebase.google.com/docs/firestore/query-data/query-cursors
As pagination is merely a way you query your data, it has no effect on how you can use this data in other ways, meaning sure you can search for a restaurant given your database design and security rules are set up right
Not sure if you should be using onSnapshot listener though, as it will return you entire collection every time something changes, which denies the whole point of using pagination
EDIT:
About real time updates: it depends on what do you want to fetch in real time. Is it only those restaurants you have loaded or all of them? Imagine you had 1.000.000 restaurants in your db, you sure wouldn't want to query for them all for real time updates. Refreshing only those that are currently loaded is pretty expensive operation in firestore as it requires canceling and creating new subscriptions every time your visible restaurants change (e.g. as you scroll through the page). So both variants are not an option
You should reconsider your app design - e.g. do you really need to live track orders of every restaurant registered? Maybe you only want those where you are an employee, or only those near you? Maybe you should restructure your database to keep orders separately from restaurants, that way you can listen for orders while still lazy loading restaurants?

React Native Geolocation is not working properly on IOS

I'm using Geolocation in React-Native to receive my current location to load object around me. Below is my code.
getCurrentPosition() {
console.log("checkLocation", "getCurrentPosition1");
navigator.geolocation.getCurrentPosition(
position => {
const { coords } = position;
if (coords !== undefined) {
console.log("checkLocation", "getCurrentPosition trigger");
this.setState({
currentCoordinate: coords,
prevCoorForGet: coords,
prevCoorForUpdate: coords
});
this.props.saveCurrentLocation({
currentLocation: {
latitude: coords.latitude,
longitude: coords.longitude
}
});
this.loadContent(coords);
}
},
error =>
console.log(
"checkLocation",
"getCurrentPosition " + JSON.stringify(error)
),
{
enableHighAccuracy: true,
timeout: 60000,
maximumAge: 3600000
}
);
}
The problem is this code working fine in the first time. But when I navigate to another scene and go back, It isn't work anymore and give me a time out error. Sometime it works, sometime it doesn't. Please help me fix it.
This one is working fine (both ios and android) in my project even working after navigating between pages and return map screen.
navigator.geolocation.getCurrentPosition(
(position) => {
// user location's latitude and longitude
let latitude = parseFloat(position.coords.latitude);
let longitude = parseFloat(position.coords.longitude);
console.log('location position: ', position);
let region = {
latitude: latitude,
longitude: longitude,
latitudeDelta: 0.0522,
longitudeDelta: 0.0321,
};
// to store region data
this.setState({region: region});
//animate to user current location
this.map.animateToRegion(region,1000)
},
(error) => console.log('position error!!!', error),
{enableHighAccuracy: false, timeout: 3000}
);
I hope it works on your project too
Edit
If still not working
/**
* when return the page this listener will trigger
*/
this.props.navigation.addListener('willFocus', (payload) => {
// call location method again
this.getLocation()
});
Try below code, this seems to work for me
import Geolocation from 'react-native-geolocation-service';
componentWillUnmount() {
Geolocation.stopObserving();
}
use your function in componentWillMount() so that every time the component mounts....it function will be executed

React Native Real-Time Issue

I am fetching Data from an API to a flatlist and its working fine the problem it's not a real time fetching, I have to refresh the screen in order to see the recent added data. How can I make the fetching real time.
export default class CategoryScreen extends Component {
constructor(props) {
super(props);
this.state = {
categories: []
}
}
componentWillMount() {
//Fetch recent products
const url = url
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
categories: responseJson.categories
})
})
}
rederItem = ({ item }) => {
return (
<CategoryFlatList title={item.cat_name} image={item.img}/>
)
}
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList style={{}}
data={this.state.categories}
renderItem={this.rederItem}
numColumns={2}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
}
If I understand your problem correctly you need to refresh the data when it was changed on the server!
If this is the case, the reason why it did not update on the list cause you did not call fetch, when u refresh the screen the fetch get called and the data get updated.
There are multiple solutions to fix this problem:
An advanced one by creating a mechanism to subscribe to the data source and update when it is changed.
Update data on user interaction (like a swipe).
A simpler way (but not that professional) by using a timer that calls the fetch and updates the state.
These are the things you can do:
1) Make a PubSub mechanism
2) Use pull to refresh in your FlatList
3) Use polling, you can either do polling by using Redux-Sagas or Redux-Observable which is the preferred method or you can do it by using timer like this
This is how you start interval
this.intervalID = setInterval(() => {
// do something
}, 5000) //time for polling in millies
This is how you can stop interval
if (this.intervalID != null) {
clearInterval(this.intervalID)
this.intervalID = null
}

Determine user location on iOS Simulator with React Native app using Geolocation API

How can make the app that will be run on the iOS simulator get the geolocation.
Currently I can only get the error output I have written for the error callback for the getCurrentPosition() or the watchPosition().
I have this code in one of my components:
componentDidMount: function(){
var geo = navigator.geolocation;
var positionOptions = {
enableHighAccuracy: true,
timeout: 3000,
maximumAge: 0,
};
var success = function(position){
this.setState({
region: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
},
});
};
var error = function(error){
alert('error watchposition:', error.code);
};
var watchID = geo.watchPosition(success, error, positionOptions);
// geo.getCurrentPosition(success, error, positionOptions);
},
Make sure you have a correct custom location in the debug menu for the simulator.
Also make sure location services enabled in the simulator for your app.