redux-observable动作必须是普通对象。使用自定义中间件进行异步操作

use*_*079 3 react-native redux rxjs5 react-redux redux-observable

当我getCurrentPositionEpic在以下代码中注释掉时,该应用程序正常运行。但是,如果我不加注释,则会出现错误:

动作必须是普通对象。使用自定义中间件进行异步操作。

export const rootEpic = combineEpics(
  fetchCategoriesEpic,
  getCurrentLocationEpic,
  getCurrentPositionEpic
)

const store = createStore(
  rootReducer,
  initialState,
  composeWithDevTools(
    applyMiddleware(createEpicMiddleware(rootEpic))
  )
)
Run Code Online (Sandbox Code Playgroud)

location.epic.js

const getCurrentPosition$ = getCurrentPositionObservable(
  { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
)

getCurrentPosition$.subscribe(
  (position) => {
    console.log(position)
    const positionObject = {
      lat: position.coords.latitude,
      lng: position.coords.longitude
    }
    //store.dispatch(updateRegion(positionObject))
    //getCurrentLocation(positionObject)
  },
  (err) => {
    console.log('Error: %s', err)
  },
  () => {
    console.log('Completed')
  })

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)
    .mapTo(() => getCurrentPosition$
      .flatMap((response) => Observable.of(
        getCurrentPositionFulfilled(response)
      ))
      .catch(error => Observable.of(getCurrentLocationRejected(error)))
    )
Run Code Online (Sandbox Code Playgroud)

下面的代码只是一个用于将本机反应转换navigator.geolocation.getCurrentPosition为可观察反应的助手,而不是用于执行回调的函数。

callBackToObservable.js

import { Observable } from 'rxjs'

export const getCurrentPositionObservable = Observable.bindCallback(
  (options, cb) => {
    if (typeof options === 'function') {
      cb = options
      options = null
    }
    navigator.geolocation.getCurrentPosition(cb, null, options)
  })
Run Code Online (Sandbox Code Playgroud)

是什么导致错误?

尝试通过商店:

export const getCurrentPositionFulfilledEpic = (action$, store) =>
  action$.ofType(GET_CURRENT_POSITION_FULFILLED)
        .mergeMap(() =>{
  console.log(store)***************** store is populated here
  return Observable.fromPromise(Geocoder.geocodePosition({
    lat: store.getState().get('searchForm').get('position').lat,***but not here
    lng: store.getState().get('searchForm').get('position').lng
  }))
    .flatMap((response) => Observable.of(
      getCurrentLocationFulfilled(response)
    ))
    .catch(error => Observable.of(getCurrentLocationRejected(error)))
}
)
Run Code Online (Sandbox Code Playgroud)

使用https://github.com/devfd/react-native-geocoder用于Geocoder.geocodePosition

jay*_*lps 5

问题是您使用mapTo。您基本上是在说“将此动作映射到一个Observable”,所以现在您的史诗返回的是Observable of Observable动作,Observable<Observable<Action>>而不只是一个Observable动作。

换句话说,您的史诗现在正在发出Observables而不是发出动作。你不是需要使用并购战略运营商一样mergeMapswitchMap等合并扁平化/内可观测链合并成顶级之一。flatMap是的别名mergeMap,顺便说一句。

export const getCurrentPositionEpic = action$ =>
  action$.ofType(GET_CURRENT_POSITION)
    .mergeMap(() => getCurrentPosition$
      .flatMap((response) => Observable.of(
        getCurrentPositionFulfilled(response)
      ))
      .catch(error => Observable.of(getCurrentLocationRejected(error)))
    )
Run Code Online (Sandbox Code Playgroud)

另一件事-您无需使用flatMapaka mergeMap将其映射getCurrentPosition$getCurrentPositionFulfilled动作,因为它是1:1。如果是一对多,则只需要它。

export const getCurrentPositionEpic = action$ =>
  action$.ofType(GET_CURRENT_POSITION)
    .mergeMap(() => getCurrentPosition$
      .map((response) => getCurrentPositionFulfilled(response))
      .catch(error => Observable.of(getCurrentLocationRejected(error)))
    )
Run Code Online (Sandbox Code Playgroud)

以您的方式使用它并没有真正的危害,但是可能会使以后维护代码的其他人感到困惑。