代码之家  ›  专栏  ›  技术社区  ›  BeniaminoBaggins

redux observable您在需要流的地方提供了“undefined”

  •  16
  • BeniaminoBaggins  · 技术社区  · 7 年前

    我使用FBSDK在Ajax请求中获取用户详细信息。所以在一部可还原的史诗中这样做是有意义的。fbskd请求的方式,它没有 .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()
    }
    

    它给出了错误:

    类型错误:您在需要流的位置提供了“未定义”。你 可以提供可观察的、承诺的、数组的或不可测的。

    我如何从史诗中返回一个可观测的,所以这个错误就消失了?

    尝试 bindCallback 由此 SO answer :

    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 回复  |  直到 7 年前
        1
  •  4
  •   artur grzesiak    7 年前

    正在查找的源代码 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 需要一个可观测的实例或与之兼容的东西( 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)))
      })
    
        2
  •  3
  •   Richard Matsen    7 年前

    看起来@artur grzesiak的答案是正确的,但为了完整起见,我是这样想的 bindCallback 可以使用。

    我对阿瑟的回答唯一的问题是,我认为我们不需要在史诗中捕捉错误,因为 fetchUserDetailsRejected 是一个错误处理操作(可能是减速器适当地处理它)。

    我用过这个参考资料 RxJs Static Public Methods: bindCallback

    给它一个f类型的函数f(x,回调),它将返回一个函数g,当调用为g(x)时,它将输出一个可观察的。

    // 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))
    
        3
  •  2
  •   Sifnos    7 年前

    我不太记得当时的工作情况 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))
    }
    

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

        4
  •  2
  •   Dhirendra    7 年前

    我认为这可能是 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)
    })
    
    推荐文章