I have methods that benefit each other and I want one of them to start after the other, but it doesn't work exactly the way I want it. In another question, I used async and await in a normal method, but I did not manage to use google APIS and nested functions.
async componentDidMount() {
await this.getCityList();
console.log(this.state.cities)
await this.currentLocation();
await this.getVenueInformation();
}
At this point, the first function works correctly and after passing the required ones, it goes to the 2nd method. In the same way, I have to put the inputs of the 2nd method into the 3rd method, but I failed.
Current location method:
currentLocation() {
Geocoder.init(...);
Geolocation.getCurrentPosition((position) => {
this.getCurrentLoc(position.coords.latitude, position.coords.longitude),
this.setState({
region: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
},
error: null,
});
}, (error) => this.setState({ error: error.message }), { enableHighAccuracy: false, timeout: 200000, maximumAge: 1000 });
}
I want my location with the above method, then I get the address information with getcurrentloc method and I plan to show some places in the vicinity in accordance with that information. However, I could not make this system work sequentially and my address is always null.
getCurrentLoc(lat, longt) {
Geocoder.from(lat, longt)
.then(json => {....
this.setState({...},
this.getLocIDS(cityName, districtName, neighborhoodName)
);
})
.catch(error => console.warn(error));
}
at this point, I get the address from the database by address to pull the id information.
getLocIDS(cityName, districtName, neighborhoodName) {
let link = ..;
fetch(link)
.then(response => response.json())
.then(res => {
this.setState({,,,,,,})
})
.catch(error => console.warn(error));
}
lastly, I want to capture the venue information, but at this point the data is entered as -1 in the database. -1 is my initial state value. I'm sure all methods work correctly, but since the processes don't run sequentially, my space search method works before updating the data in the previous functions state.
getVenueInformation() {
let link = ...
fetch(link)
.then(response => response.json())
.then(venues => {
this.setState({
markers: venues,
isLoading: false,
})
})
};
database input return: >>>>> SELECT * FROM mekanlar WHERE mekanlar.mahalle_no="-1";
You don't show how you pass the information from one method to the other.
If you do it by use of this.state, that is where your problem is.
this.setState will not update the state synchronously. So you might not have the right value in this.state in your next function call.
To make sure the data flow is correct, it makes more sense to return the values explicitly, even if you do setState internally.
async componentDidMount() {
const cityList = await this.getCityList();
console.log(cityList)
const location = await this.currentLocation(cityList);
const venueInformation = await this.getVenueInformation(location);
}
Related
I want to use mapview marker for show direction/route between user location and destination in react-native and a json service that gave the route as points.
now i want when user moves and her location changes, something like OnCoordinateChange for marker coordinate, call a function so i can send real-time start-point location to the router service and get new direction based on new location.
How can i do this?
here is some parts of my code:
(don't pay attention to that piece of #$%# code between two comment blocks!)
componentDidMount() {
//User Location
navigator.geolocation.getCurrentPosition(
position => {
fetch('https://api.openrouteservice.org/v2/directions/foot-walking?api_key='+ OsmDirectionApiKet +'&start='+position.coords.longitude+','+position.coords.latitude+'&end={}')
.then((response) => response.json())
.then((responseJson) => {
/*********
Began some of code that just me and god can understand why and has nothing effect on question!!!
**********/
var PolylineGetCoordinates = responseJson.features[0].geometry.coordinates;
var PolylineFinalCoordinates = [];
for(i=0;i<PolylineGetCoordinates.length;i++){
var obj = {};
obj.longitude = PolylineGetCoordinates[i][0];
obj.latitude = PolylineGetCoordinates[i][1];
PolylineFinalCoordinates.push(obj);
}
/*********
End some of $%## code!!!
*********/
this.setState({
PolylineCoordinates :PolylineFinalCoordinates
});
})
.catch((error) => {
console.error(error);
});
},
error => {
this.setState({
error: 'error'
});
}
);
}
//-------------------
<Polyline coordinates={PolylineCoordinates} />
well found a {SIMPLE} solution!
just moved the codes in componentDidMount() in another function, and changed the codes in componentDidMount to:
componentDidMount() {
this.getCurrentLocation;
setInterval(this.getCurrentLocation, 500);
}
and added this line to constructor:
this.getCurrentLocation = this.getCurrentLocation.bind(this);
I am passing params from my API to vue-head but every time I do that it send me undefined in the head this is the code:
export default {
data: () => ({
errors: [],
programs: [],
}),
methods: {
getProgram() {
this.api.http.get(`videos/program/${this.programSlug}`)
.then(response => {
this.programs = response.data
})
.catch(error => {
this.errors = error
});
}
},
head: {
title: function() {
return {
inner: this.programs.name,
separator: '|',
complement: 'Canal 10'
};
}
}
}
any idea what I am doing wrong with my code??
First verify you are fetching the information correctly. Use console log and go to network tab and verify you are fetching the data correct, you might have to comment out vue-head. But what I think is that the problem might be due to vue-head rendering before the api call finishes then no data is being passed.
If you are using vue-router this can be easily solved with beforeRouteEnter() hook. But if not! apparently vue-head has an event that you can emit to update the component after render.
I haven't tried this but it should work. you can add the function below to your methods and call it after the promise is resolved i.e in the then closure.
methods: {
getProgram() {
this.api.http.get(`videos/program/${this.programSlug}`)
.then(response => {
this.programs = response.data
this.$emit('updateHead')
})
.catch(error => {
this.errors = error
});
}
}
How can I set a timeout when fetching an API?
What I want exactly is to try to fetch the data for 10 seconds, if it fails then I want to load the data (saved previously and updated every time that the fetch works) from AsyncStorage.
Probably how I'm doing this is not the correct way, I'm kinda noob at programming (xD). However, this code works just fine on the emulator but does not work on my phone (android). The AsyncStorage seems not to work.
Here is my code:
constructor(){
super()
this.state = {
fetching: false,
data: []
}
}
componentWillMount(){
this.setState({ fetching: true })
fetch('http://192.168.1.122:3000/categories.json')
.then(res => res.json())
.then(res => {
this.setState({
data: res,
fetching: false
})
})
.then(res => {
AsyncStorage.setItem(
'#Data:Monumentos',
JSON.stringify(res)
)
})
.catch(AsyncStorage.getItem(
'#Data:Monuments',
(err, dados) => {
if(err) {
console.error('Error loading monuments', err)
} else {
const monuments = JSON.parse(dados)
this.setState({
data: monuments
})
}
}
))
}
Hope you can help me. Thank you!
RN uses whatwg-fetch which doesn't have a timeout. You can work around it by using whatwg-fetch-timeout as mentioned here
That would be simpler than what Micheal above in the comments linked too which is to use Promise.race and setTimeout. Admittedly, pretty clever.
I'm trying to use react native Geolocation to getCurrentPosition and then as soon as the position is returned, use react native geocoder to use that position to get the location. I'm using redux-observable epics to get all of this done.
Here are my two epics:
location.epic.js
import { updateRegion } from '../map/map.action'
import Geocoder from 'react-native-geocoder'
export const getCurrentLocationEpic = action$ =>
action$.ofType(GET_CURRENT_LOCATION)
.mergeMap(() =>
Observable.fromPromise(Geocoder.geocodePosition(makeSelectLocation()))
.flatMap((response) => Observable.of(
getCurrentLocationFulfilled(response)
))
.catch(error => Observable.of(getCurrentLocationRejected(error)))
)
export const getCurrentPositionEpic = action$ =>
action$.ofType(GET_CURRENT_POSITION)
.mergeMap(() =>
navigator.geolocation.getCurrentPosition(
(position) => Observable.of(
updateRegion(position),
getCurrentLocation(position)
),
error => Observable.of(getCurrentPositionRejected(error)),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
).do(x => console.log(x))
).do(x => console.log(x))
As soon as the app starts, this code executes:
class Vepo extends Component {
componentDidMount() {
const { store } = this.context
this.unsubscribe = store.subscribe(() => { })
store.dispatch(fetchCategories())
store.dispatch(getCurrentPosition())
}
fetchCategories() is an action that has an epic too, but that is working. dispatching the getCurrentPosition() action runs through the epic above. The only output that I can see is that my reducer handles getLocationRejected() as it console logs this:
there was an issue getting your current location: Error: invalid position: {lat, lng} required
at Object.geocodePosition (geocoder.js:15)
at MergeMapSubscriber.project (location.epic.js:17)
at MergeMapSubscriber._tryNext (mergeMap.js:120)
at MergeMapSubscriber._next (mergeMap.js:110)
at MergeMapSubscriber.Subscriber.next (Subscriber.js:89)
at FilterSubscriber._next (filter.js:88)
at FilterSubscriber.Subscriber.next (Subscriber.js:89)
at Subject.next (Subject.js:55)
at Object.dispatch (createEpicMiddleware.js:72)
at Object.dispatch (devTools.js:313)
Here is my reducer:
const searchPage = (
initialLocationState = initialState.get('searchForm').get('location'),
action: Object): string => {
switch (action.type) {
case GET_CURRENT_LOCATION_FULFILLED: {
return action.payload
}
case GET_CURRENT_LOCATION_REJECTED: {
console.log('there was an issue getting your current location: ',
action.payload)
return initialLocationState
}
case GET_CURRENT_POSITION_REJECTED: {
console.log('there was an issue getting your current position: ',
action.payload)
return initialLocationState
}
default:
return initialLocationState
}
}
Is there anything obvious I am doing wrong? My attempt to debug by adding .do(x => console.log(x)) does nothing, nothing is logged to the console. updateRegion() never does fire off because that dispatches an action and the reducer UPDATE_REGION never executes. But the execution must make it into the success case of getCurrentPosition() eg:
(position) => Observable.of(
updateRegion(position),
getCurrentLocation(position)
),
must execute because the getCurrentLocation(position) does get dispatched.
Where am I going wrong?
What would be your technique for using an epic on a function which takes a callback function? getCurrentPosition() takes a callback and the callback handles the payload. Basically if you remove Observable.of( from inside getCurrentPosition(), that's how getCurrentPosition() is correctly used - and has been working for me without redux-observable.
Wrapping anything in a custom Observable is fairly simple, very similar to creating a Promise except Observables are lazy--this is important to understand! RxJS Docs
In the case of geolocation, there are two main APIs, getCurrentPosition and watchPosition. They have identical semantics except that watchPosition will call your success callback every time the location changes, not just a single time. Let's use that one since it's natural to model it as a stream/Observable and most flexible.
function geolocationObservable(options) {
return new Observable(observer => {
// This function is called when someone subscribes.
const id = navigator.geolocation.watchPosition(
(position) => {
observer.next(position);
},
error => {
observer.error(error);
},
options
);
// Our teardown function. Will be called if they unsubscribe
return () => {
navigator.geolocation.clearWatch(id);
};
});
}
geolocationObservable({ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 })
.subscribe(
position => console.log(position),
e => console.error(e)
);
// will log every time your location changes, until you unsubscribe
Since it's now an Observable, if you only want the current location you can just do .take(1).
So using it inside your epic might be like this
// If you want, you could also use .share() to share a single
// underlying `watchPosition` subscription aka multicast, but
// that's outside the scope of the question so I don't include it
const currentPosition$ = geolocationObservable({
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000
});
export const getCurrentPositionEpic = action$ =>
action$.ofType(GET_CURRENT_POSITION)
.mergeMap(() =>
currentPosition$
.take(1) // <----------------------------- only the current position
.mergeMap(position => Observable.of(
updateRegion(position),
getCurrentLocation(position)
))
.catch(error => Observable.of(
getCurrentPositionRejected(error)
))
);
As a side note, you might not need to dispatch both updateRegion() and getCurrentLocation(). Could your reducers just listen for a single action instead, since they both seem to be signalling the same intent?
I need to pass some data from one screen to another, but I don't know how to do it. I've searched and I read about Redux, but it is a bit complicated since I never used it and most of the tutorials are confusing for a newcomer. But if I could do it without Redux, that would be better.
So, when I click in a button, It runs this:
onSearch() {
var listaCarros = fetch(`URL`, {
method: 'GET',
})
.then((response) => { return response.json() } )
.then((responseJson) => {
console.log(responseJson)
})
}
and I want to pass the data I get from this, to another screen.
Im using router-flux, if that matters.
you can save the response in state of your current component like
onSearch() {
var listaCarros = fetch(`URL`, {
method: 'GET',
})
.then((response) => { return response.json() } )
.then((responseJson) => {
console.log(responseJson);
/*for react-native-router-flux you can simply do
Actions.secondPage({data:responseJson}); and you will get data at SecondPage in props
*/
this.setState({
dataToPass :responseJson
});
})
}
then below in return like you want to pass data to a new component having named as SecondPage, you can do it in following way
render(){
return(
{this.state.dataToPass && <SecondPage data ={this.state.dataToPass}>} //you will get data as props in your second page
);
}