您可以在redux-observable中提供“未定义”的流

时间:2018-10-03 04:40:55

标签: react-native react-redux redux-observable react-native-fbsdk

我正在使用fbsdk在ajax请求中获取用户详细信息。因此,以可观察到的史诗形式进行此操作很有意义。 fbsdk请求的处理方式,它没有.map().catch(),它接收成功和失败回调:

代码:

export const fetchUserDetailsEpic: Epic<*, *, *> = (
  action$: ActionsObservable<*>,
  store
): Observable<CategoryAction> =>
  action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
    getDetails(store)
  })

const getDetails = store => {
  console.log(store)
  let req = new GraphRequest(
    '/me',
    {
      httpMethod: 'GET',
      version: 'v2.5',
      parameters: {
        fields: {
          string: 'email,first_name,last_name'
        }
      }
    },
    (err, res) => {
      if (err) {
        store.dispatch(fetchUserDetailsRejected(err))
      } else {
        store.dispatch(fetchUserDetailsFulfilled(res))
      }
    }
  )

  return new GraphRequestManager().addRequest(req).start()
}

出现错误:

  

TypeError:您提供了“未定义”的预期流。您   可以提供Observable,Promise,Array或Iterable。

我如何从史诗中返回可观察到的东西,以使该错误消失?

SO answer尝试bindCallback

const getDetails = (callBack, details) => {
  let req = new GraphRequest(
    '/me',
    {
      httpMethod: 'GET',
      version: 'v2.5',
      parameters: {
        fields: {
          string: 'email,first_name,last_name'
        }
      }
    },
    callBack(details)
  )

  new GraphRequestManager().addRequest(req).start()
}

const someFunction = (options, cb) => {
  if (typeof options === 'function') {
    cb = options
    options = null
  }
  getDetails(cb, null)
}

const getDetailsObservable = Observable.bindCallback(someFunction)

export const fetchUserDetailsEpic: Epic<*, *, *> = (
  action$: ActionsObservable<*>
): Observable<CategoryAction> =>
  action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
    getDetailsObservable()
      .mergeMap(details => {
        return Observable.of(fetchUserDetailsFulfilled(details))
      })
      .catch(error => Observable.of(fetchUserDetailsRejected(error)))
  })

遇到相同的错误

4 个答案:

答案 0 :(得分:4)

查看GraphRequestManager .start的源代码:

start(timeout: ?number) {
  const that = this;
  const callback = (error, result, response) => {
    if (response) {
      that.requestCallbacks.forEach((innerCallback, index, array) => {
        if (innerCallback) {
          innerCallback(response[index][0], response[index][1]);
        }
      });
    }
    if (that.batchCallback) {
      that.batchCallback(error, result);
    }
  };

  NativeGraphRequestManager.start(this.requestBatch, timeout || 0, callback);
}

如您所见,它确实不返回任何内容,因此有效地undefined。 Rx mergeMap需要Observable实例或与其兼容的实例(more info)。

由于您调度了进一步的操作,因此可以像这样修改原始代码:

export const fetchUserDetailsEpic: Epic<*, *, *> = (
  action$: ActionsObservable<*>,
  store
): Observable<CategoryAction> =>
  action$.ofType(FETCH_USER_DETAILS).do(() => { // .mergeMap changed to .do
    getDetails(store)
  })

const getDetails = store => {
  console.log(store)
  let req = new GraphRequest(
    '/me',
    {
      httpMethod: 'GET',
      version: 'v2.5',
      parameters: {
        fields: {
          string: 'email,first_name,last_name'
        }
      }
    },
    (err, res) => {
      if (err) {
        store.dispatch(fetchUserDetailsRejected(err))
      } else {
        store.dispatch(fetchUserDetailsFulfilled(res))
      }
    }
  )

  return new GraphRequestManager().addRequest(req).start()
}

说实话,我发现您的第二次尝试更好/更少了。要使其正常工作,您可以执行以下操作:

const getDetails = Observable.create((observer) => {
  let req = new GraphRequest(
    '/me',
    {
      httpMethod: 'GET',
      version: 'v2.5',
      parameters: {
        fields: {
          string: 'email,first_name,last_name'
        }
      }
    },
    (error, details) => {
      if (error) {
        observer.error(error)
      } else {
        observer.next(details)
        observer.complete()
      }
    }
  )

  new GraphRequestManager().addRequest(req).start()
})

export const fetchUserDetailsEpic: Epic<*, *, *> = (
  action$: ActionsObservable<*>
): Observable<CategoryAction> =>
  action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
    getDetails()
      .map(details => fetchUserDetailsFulfilled(details)) // regular .map should be enough here
      .catch(error => Observable.of(fetchUserDetailsRejected(error)))
  })

答案 1 :(得分:3)

@artur grzesiak似乎提供了正确的答案,但出于完整性考虑,这就是我认为可以使用bindCallback的方式。

我对Artur的回答唯一的问题是,我认为我们不需要抓住史诗中的错误,因为fetchUserDetailsRejected是一个错误处理操作(大概是reducer适当地处理了它)。 / p>

我使用了此引用RxJs Static Public Methods: bindCallback

  

给它一个类型为f(x,callback)的函数f,它将返回一个函数g,当它被称为g(x)时将输出一个Observable。

// This callback receives the results and returns one or other action (non-observable)
const callback = (err, res) => {
  return err 
    ? fetchUserDetailsRejected(err)
    : fetchUserDetailsFulfilled(res)
}

// Here is the graph request uncluttered by concerns about the epic
const getDetails = (store, callback) => {
  console.log(store)
  let req = new GraphRequest(
    '/me',
    {
      httpMethod: 'GET',
      version: 'v2.5',
      parameters: {
        fields: {
          string: 'email,first_name,last_name'
        }
      }
    },
    callback
  )
  new GraphRequestManager().addRequest(req).start()
}

// This bound function wraps the action returned from callback in an Observable
const getDetails$ = Observable.bindCallback(getDetails).take(1)

// The epic definition using bound callback to return an Observable action
export const fetchUserDetailsEpic: Epic<*, *, *> = 
  (action$: ActionsObservable<*>, store): Observable<CategoryAction> =>
    action$.ofType(FETCH_USER_DETAILS).mergeMap(() => getDetails$(store))

答案 2 :(得分:2)

在使用redux-observable之前,我不太记得RxJS >= 6的工作方式,但是我会尽力帮助;)

首先,您不需要派遣自己,redux-observable会为您完成任务。 In this article,他们展示了幕后工作原理,因此他们将其称为调度,但您不必这样做。在新的实现中,他们删除了store作为第二个参数,而赞成使用state流:

const epic = (action$, store) => { ... //before
const epic = (action$, state$) => { ... //after

但最重要的是,您遇到的问题是您没有返回动作流,而是返回了一个(已分派的)动作。 From their website

  

该函数需要一系列操作并返回一系列操作。

因此,我认为一种快速的解决方案是从回调中返回可观察值:

(err, res) => {
  if (err) {
    return Observable.of(fetchUserDetailsRejected(err))
  }
  return Observable.of(fetchUserDetailsFulfilled(res))
}

我将根据您的评论更新答案。祝你好运!

答案 3 :(得分:2)

我相信这似乎是undefined的可能原因。您正在undefined回调函数中返回mergeMap

action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
    getDetails(store)
})

应该是

action$.ofType(FETCH_USER_DETAILS).mergeMap(() => getDetails(store))

action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
    return getDetails(store)
})