我尝试使用本地Geolocation对getCurrentPosition
作出反应,然后在返回位置后立即使用react native geocoder来获取该位置。我使用redux-observable史诗来完成所有这些工作。
这是我的两部史诗:
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))
只要应用程序启动,此代码就会执行:
class Vepo extends Component {
componentDidMount() {
const { store } = this.context
this.unsubscribe = store.subscribe(() => { })
store.dispatch(fetchCategories())
store.dispatch(getCurrentPosition())
}
fetchCategories()
也是一部具有史诗的动作,但这是有效的。调度getCurrentPosition()
动作贯穿上面的史诗。我能看到的唯一输出是我的reducer处理getLocationRejected()
,因为它控制台记录了这个:
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)
这是我的减速机:
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
}
}
有什么明显我做错了吗?我通过添加.do(x => console.log(x))
进行调试的尝试什么也没做,没有任何内容记录到控制台。 updateRegion()
永远不会触发,因为它会调度一个动作,而减速器UPDATE_REGION
永远不会执行。但执行必须使其成为getCurrentPosition()
的成功案例,例如:
(position) => Observable.of(
updateRegion(position),
getCurrentLocation(position)
),
必须执行,因为getCurrentLocation(position)
确实已分派。
我哪里错了?
答案 0 :(得分:3)
在采用回调函数的函数上使用史诗的技巧是什么? getCurrentPosition()接受回调,回调处理有效负载。基本上,如果你删除Observable.of(来自getCurrentPosition()内部,那就是getCurrentPosition()是如何被正确使用的 - 并且在没有redux-observable的情况下一直在为我工作。
在自定义Observable中包装任何内容都非常简单,非常类似于创建Promise,除了Observables是懒惰的 - 这一点很重要! RxJS Docs
在地理位置的情况下,有两个主要的API,getCurrentPosition
和watchPosition
。它们具有相同的语义,除了watchPosition
每次位置更改时都会调用您的成功回调,而不仅仅是一次。让我们使用那个,因为它很自然地将其建模为流/可观察且最灵活。
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
由于它现在是一个Observable,如果你只想要当前的位置,你可以.take(1)
。
所以在史诗中使用它可能就像这样
// 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)
))
);
作为旁注,您可能不需要同时发送updateRegion()
和getCurrentLocation()
。你的减速器是否可以只听一个动作,因为它们似乎都表示同样的意图?