наблюдаемую при помощи редукса вы указали «неопределенное» там, где ожидался поток - PullRequest
0 голосов
/ 03 октября 2018

Я использую 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: Вы указали 'undefined', где ожидался поток.Вы можете предоставить Observable, Promise, Array или Iterable.

Как вернуть наблюдаемое из эпоса, чтобы эта ошибка исчезла?

Попытка на bindCallback из этого SO ответ :

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 голосов
/ 12 октября 2018

Похоже, что @artur grzesiak имеет правильный ответ, но для полноты я думаю, что можно использовать bindCallback.

Единственная проблема, с которой я столкнулся с ответом Артура, - я не думаю, что мынужно отловить ошибку в эпопее, поскольку fetchUserDetailsRejected является действием по обработке ошибок (предположительно, редуктор обрабатывает его соответствующим образом).

Я использовал эту ссылку Статические открытые методы RxJs: bindCallback

Дайте ему функцию f типа f (x, обратный вызов), и она вернет функцию 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))
0 голосов
/ 05 октября 2018

Я полагаю, это кажется возможной причиной для 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)
})
0 голосов
/ 07 октября 2018

Просмотр исходного кода 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 или что-то совместимое с ним ( дополнительная информация ).

Поскольку вы отправляете дальнейшие действия, вы можете изменить свой исходный код следующим образом:

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)))
  })
0 голосов
/ 03 октября 2018

Я не очень хорошо помню, как работал redux-observable перед использованием RxJS >= 6, но я постараюсь помочь;)

Во-первых, вам не нужно отправлять себя, наблюдаемая редукция будетсделай это для тебя. В этой статье они показывают, как это работает под капотом, поэтому они вызывают диспетчеризацию, но вам не нужно.В новой реализации они удалили store в качестве второго аргумента в пользу потока state:

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

Но самое главное, проблема, с которой вы столкнулись, заключается в том, что вы не возвращаетепоток действий , но одно (отправленное) действие. С их сайта :

Это функция, которая принимает поток действий и возвращает поток действий.

Так что я думаю, что быстрорешение было бы вернуть наблюдаемые из вашего обратного вызова:

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

Я буду обновлять ответ на основе ваших комментариев.Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...