3

我正在尝试使用反应原生地理定位getCurrentPosition然后一旦返回位置,使用反应原生地理编码器使用该位置来获取位置。我正在使用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()动作贯穿上面的史诗。我能看到的唯一输出是我的减速器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)确实被调度了。

我哪里错了?

4

1 回答 1

5

您在采用回调函数的函数上使用史诗的技术是什么?getCurrentPosition() 接受回调,回调处理有效负载。基本上,如果你从 getCurrentPosition() 中删除 Observable.of(,这就是正确使用 getCurrentPosition() 的方式——并且在没有 redux-observable 的情况下一直为我工作。

在自定义的 Observable 中包装任何东西都相当简单,与创建 Promise 非常相似,只是 Observable 是惰性的——理解这一点很重要!RxJS 文档

在地理定位的情况下,有两个主要的 API,getCurrentPositionwatchPosition. 它们具有相同的语义,除了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()。你的 reducer 是否可以只监听一个动作,因为它们似乎都在发出相同的意图?

于 2017-05-02T22:42:27.583 回答