Redux-observable возвращает некоторые образцы данных

Я использую наблюдаемый с редуксом, и мне нужно вернуть некоторые образцы данных в виде наблюдаемого. У меня есть следующий код в одном из моих эпиков

const sampleFilteredStores = Observable.of([{ type: 'FILTERED_STORES', store: 'a' }, { type: 'FILTERED_STORES', store: 'b' }]);
const filteredStores$ = action$.ofType('SEARCH_STORES').mapTo(Observable.of(sampleFilteredStores).mergeAll());
return filteredStores$;

Однако, когда я запускаю это, я получаю сообщение об ошибке

instrument.js:56 Неперехваченная ошибка: действия должны быть простыми объектами. Используйте специальное ПО промежуточного слоя для асинхронных действий.(…)

Что я здесь делаю не так и как это исправить?


person tmp dev    schedule 06.06.2017    source источник


Ответы (1)


Расследование

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

const somethingEpic = action => {
  const sampleFilteredStores = Observable.of([
    { type: 'FILTERED_STORES', store: 'a' },
    { type: 'FILTERED_STORES', store: 'b' }
  ]);
  const filteredStores$ = action$.ofType('SEARCH_STORES')
    .mapTo(
      Observable.of(sampleFilteredStores)
        .mergeAll()
    );

  return filteredStores$;
};

Как именно вы форматируете свой код, зависит от вас, но я лично нахожу что-то подобное этому гораздо более читабельному. Это поможет вам в отладке, а также существенно поможет будущим специалистам по сопровождению вашего кода понять ваши намерения.

картаКуда

Теперь я сразу вижу одну проблему: вы передаете Observable в mapTo, что очень необычно для Rx. Это, конечно, не неправильно в 100% случаев, но в 99,99% и даже в 0,01% были бы гораздо более четкие способы показать желаемое намерение.

Observable.of

Копаясь дальше, я вижу два варианта использования Observable.of.

Первое, что бросается в глаза, это то, что вы передаете Observable в Observable.of: Observable.of(sampleFilteredStores) Здесь применяется тот же совет, что и в mapTo, это очень редко и не рекомендуется, потому что это создает Observable более высокого порядка без необходимости. Я вижу, что вы используете mergeAll(), чтобы сгладить его, но это дает вам Observable, который в основном идентичен тому, что sampleFilteredStores без косвенности.

Когда я копаю еще глубже, я замечаю еще одну тонкую, но важную вещь: вы передаете массив действий в Observable.of. Это также очень подозрительно, потому что это означает, что вы создаете Observable, который просто генерирует массив из двух действий, а не испускает эти два действия последовательно напрямую. Если позже вы намеревались, вместо этого вам нужно было передать объекты непосредственно в качестве самих аргументов. Observable.of(action1, action2, action3, ...etc). Возможно, вы запутались, увидев, как кто-то использует Observable.from для передачи массива, но это отличается от Observable.of.

Первопричина

Объединив эти открытия, я теперь вижу, что этот эпос на самом деле испускает Observable, а не действия, поэтому вы получаете сообщение об ошибке от redux. Сам этот Observable на самом деле будет генерировать массив действий, поэтому, даже если вы сгладите этот Observable, вы все равно получите ту же ошибку.

Решение

Похоже, что предоставленный код, вероятно, придуман либо для упрощения вашего вопроса, либо для того, чтобы вы изучали Rx или наблюдаемый с редукцией. Но в этом конкретном случае я полагаю, что вы хотели прослушать SEARCH_STORES и при получении последовательно отправить два действия типа FILTERED_STORES с разными значениями store.

Используя идиоматический Rx, это может выглядеть примерно так:

const somethingEpic = action => {
  return action$.ofType('SEARCH_STORES')
    .mergeMap(() => Observable.of(
      { type: 'FILTERED_STORES', store: 'a' },
      { type: 'FILTERED_STORES', store: 'b' }
    ))
};

Здесь мы используем mergeMap, но так как Observable.of мы выравниваем в испускаемых синхронно, мы могли бы также использовать switchMap или concatMap, они имели бы такой же суммарный эффект — но это не относится к Observables, которые испускают асинхронно! Поэтому обязательно изучите различные операторы стратегии выравнивания.

Эту цепочку можно описать так: всякий раз, когда мы получаем объект со свойством type равно SEARCH_STORES, сопоставляем его с Observable из двух объектов (FILTERED_STORES действий), которые испускаются последовательно и синхронно.

Закрытие

Надеюсь, это поможет! Одна вещь, которую следует иметь в виду при изучении и использовании redux-observable, заключается в том, что почти полностью «просто RxJS» имеет дело с объектами, которые являются «действиями». Таким образом, нормальный идиоматический Rx является нормальным идиоматическим редукционно-наблюдаемым. То же самое с проблемами, с которыми вы можете столкнуться. Единственная реальная разница заключается в том, что redux-observable предоставляет единственный оператор ofType в качестве сокращения для filter (как описано в документах). Если в будущем у вас возникнут проблемы с Rx, возможно, вам будет полезно реорганизовать ваши примеры, чтобы использовать filter, и сформулировать их независимо от наблюдаемых с избыточностью, поскольку сообщество Rx, очевидно, намного больше!

person jayphelps    schedule 06.06.2017
comment
Большое спасибо за объяснение, это было действительно полезно. В следующий раз отформатирует код лучше. - person tmp dev; 07.06.2017