Наблюдаемый Redux запрос POST ajax никогда не отправляет сетевой запрос

У меня есть этот redux-observable эпик, который POST является телом json для моего бэкэнда, но на самом деле он никогда не получает чтобы отправить фактический сетевой запрос. Он использует Rx.DOM.Request.post (url, [body]) (я думаю? пожалуйста, просмотрите мой импорт, чтобы подтвердить). Я могу убедиться, что сетевой запрос никогда не выходит из моего приложения, не говоря уже о моем бэкэнде:

import { Observable } from 'rxjs'
import 'redux-observable'
import {
  UPLOAD_IMAGE,
  UPLOAD_IMAGE_FULFILLED,
  UPLOAD_IMAGE_REJECTED,
  UPLOAD_PRODUCT,
  uploadImageFulfilled,
  uploadImageRejected,
  uploadProductFulfilled,
  uploadProductRejected
} from './addForm.action'
import {
  updateAlertModalIsOpen,
  updateAlertModalMessage,
  updateAlertModalTitle
} from '../alert-modal/alertModal.action'
import 'rxjs/add/operator/catch'
import { RNS3 } from 'react-native-aws3'
import { ajax } from 'rxjs/observable/dom/ajax'

export const uploadProductEpic = action$ =>
  action$.ofType(UPLOAD_PRODUCT)
    .mergeMap(action => {
      ajax.post(
        'http://192.168.20.3:4000/products', 
        action.payload,
        { 'Content-Type': 'application/json' })
    })
    .map(response => uploadProductFulfilled(response))
    .catch(error => Observable.of(uploadProductRejected(error)))

Он вызывается нажатием кнопки:

      onPress={() => {
       let product = {
              "name": props.name,
              "brand": props.brand,
              "description": props.description,
              "image": "fakeUrl"
          }

        props.uploadProduct(JSON.stringify(product))

это содержимое объекта action в приведенной выше эпопее:

payload: "{"name":"v","brand":"v","description":"v","image":"fakeUrl"}"
type: "UPLOAD_PRODUCT"

Это потому, что мой json использует все двойные кавычки без выходов?

Я могу проверить строку кода в эпике, который выполняет сообщение ajax, запускается при нажатии кнопки, и при первом нажатии кнопки он завершает отправку uploadProductRejected(error), даже не выполняя сетевой запрос, и где ошибка, которая отправляется в действие uploadProductRejected - это просто { }, и при последующих нажатиях кнопки оно даже не отправляет отклоненное или выполненное действие.

Есть идеи, почему он отклоняется и почему он даже не пытается выполнить сетевой запрос?


person BeniaminoBaggins    schedule 22.05.2017    source источник


Ответы (1)


btw - документация, на которую вы указываете для _1 _ предназначен для v4 RxJS, но в вашем коде используется v5. Документация для v5 находится здесь, однако Observable.ajax находится еще не задокументирован, к сожалению, но он довольно близок к версии v4 и имеет в основном очевидный API.


Что касается вашего кода, сначала нам нужно сделать несколько домашних вещей.

Вероятно, вам не стоит помещать map и catch снаружи в Observable верхнего уровня. Если вы это сделаете, любые ошибки внутри вашего mergeMap могут распространяться и достигать action$.ofType, что означает, что ваш эпик будет завершен, потому что вы поймаете ошибку и вместо этого переключитесь с ошибочной цепочки верхнего уровня на Observable.of(uploadProductRejected(error)).

Вместо этого вы хотите изолировать свои Observables, поместив эту логику внутри mergeMap:

export const uploadProductEpic = action$ =>
  action$.ofType(UPLOAD_PRODUCT)
    .mergeMap(action => {
      ajax.post(
        'http://192.168.20.3:4000/products', 
        action.payload,
        { 'Content-Type': 'application/json' }
      )
        .map(response => uploadProductFulfilled(response))
        .catch(error => Observable.of(uploadProductRejected(error)))
    });

Хотя это всего лишь обычный RxJS, в режиме Redux-Observable это особенно важно, поскольку вы не хотите, чтобы ваш эпик завершался, когда один запрос терпит неудачу. Это описано в документации здесь. Если это сбивает с толку, я рекомендую потратить некоторое время, чтобы полностью понять, как работают наблюдаемые цепочки. Помимо чтения документации и руководств (которые полезны), также поэкспериментируйте с REPL, например с jsbin.


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

Хотя вы его не предоставили, я могу предположить, основываясь на вашем коде, что это что-то вроде:

TypeError: вы указали undefined там, где ожидался поток. Вы можете предоставить Observable, Promise, Array или Iterable. в subscribeToResult

Он также будет включать трассировку стека, которая сначала должна указывать на что-то вроде MergeMapSubscriber._innerSub, что означает, что эту ошибку вызывает оператор mergeMap. Если мы посмотрим на то, как вы используете mergeMap, то увидим, что на самом деле мы ничего не возвращаем! Поскольку вы используете стрелочную функцию с фигурными скобками, это означает, что вам нужно явно указать return.

export const uploadProductEpic = action$ =>
  action$.ofType(UPLOAD_PRODUCT)
    .mergeMap(action => { // <--------------------------- whoops!
      ajax.post(
        'http://192.168.20.3:4000/products', 
        action.payload,
        { 'Content-Type': 'application/json' })
    })

Вы, вероятно, хотели использовать стрелочную функцию без фигурных скобок, чтобы она имела неявный возврат.

person jayphelps    schedule 23.05.2017
comment
Спасибо за очень простые для понимания объяснения! - person BeniaminoBaggins; 23.05.2017