Permalink
Browse files

feat(adapters): remove adapters support

BREAKING CHANGE: Support for adapters has been removed. Adapters were previously used to transform the `action$` Observable into some other stream-library primitive; like Most.js, Bacon, RxJS v4, etc. While rarely used, if you would like this functionality the MIGRATION.md guide gives an example: https://redux-observable.js.org/MIGRATION.html#setting-up-the-middleware
  • Loading branch information...
jayphelps committed Jun 15, 2018
1 parent 0b4f389 commit 87a5f86bae833f0ccbd2218ba5d730cf4b955cc7
Showing with 36 additions and 100 deletions.
  1. +33 −0 MIGRATION.md
  2. +0 −19 README.md
  3. +0 −34 docs/FAQ.md
  4. +0 −3 docs/api/createEpicMiddleware.md
  5. +0 −6 index.d.ts
  6. +3 −18 src/createEpicMiddleware.js
  7. +0 −20 test/createEpicMiddleware-spec.js
@@ -26,6 +26,8 @@ There will likely be a backwards compatibility layer provided with RxJS that wil
## Setting up the middleware
### rootEpic
In 1.0.0 you no longer provide your root Epic to `createEpicMiddleware`. Instead, you call `epicMiddleware.run(rootEpic)` on the instance of the middleware _after_ you have created your store with it.
```ts
@@ -41,6 +43,37 @@ This new API also gives you the ability to easily add Epics later, as in async l
The optional configuration/options argument to `createEpicMiddleware` for providing dependencies, adapters, etc is now the first and only argument to `createEpicMiddleware(options)`.
### Adapters
Adapters are no longer supported, but you can achieve the same behavior by applying the transforms in a custom root Epic.
Here's an example of converting the Observables to Most.js streams:
```js
import most from 'most';
import { from } from 'rxjs';
// a Most.js implementatin of combineEpics
const combineEpics = (...epics) => (...args) =>
most.merge(
...epics.map(epic => epic(...args))
);
const rootEpic = (action$, state$, ...rest) => {
const epic = combineEpics(epic1, epic2, ...etc);
// action$ and state$ are converted from Observables to Most.js streams
const output = epic(
most.from(action$),
most.from(state$),
...rest
);
// convert Most.js stream back to Observable
return from(output);
};
```
## Actions emitted by your epics are now scheduled on a queue
In 1.0.0 we now subscribe to your root Epic, and dispatch actions emitted by it, using the queueScheduler from RxJS. This is a bit hard to explain (and understand) but as the name suggests, a queue is used. If the queue is empty, the action is emitted as usual, but if that action synchronously causes other actions to be emitted they will be queued up until the call stack of the first action returns.
@@ -48,25 +48,6 @@ npm install --save redux-observable
**IMPORTANT:** redux-observable does not add any of the RxJS operators to the `Observable.prototype` so you will need to import the ones you use or import all of them in your entry file. [Learn more](http://redux-observable.js.org/docs/Troubleshooting.html#rxjs-operators-are-missing-eg-typeerror-actionoftypeswitchmap-is-not-a-function).
##### Optional Adapters
Epics use RxJS v5 by default. You can use other stream libraries (other than RxJS v5) by using an Adapter.
* [RxJS v4](https://github.com/redux-observable/redux-observable-adapter-rxjs-v4)
* [most.js](https://github.com/redux-observable/redux-observable-adapter-most)
* [xstream](https://github.com/vic/redux-observable-adapter-xstream)
You can write your own adapter too:
```js
const adapter = {
input: input$ => /* convert Observable to your preferred stream library */,
output: output$ => /* convert your preferred stream back to an Observable */
};
```
See the existing adapters for examples. Keep in mind that while you still need RxJS v5 installed, redux-observable only pulls in the minimum amount of RxJS it needs internally--it doesn't import _all_ of RxJS.
##### UMD
We publish a UMD build inside our npm package. You can use it via the [unpkg](https://unpkg.com/) CDN:

This file was deleted.

Oops, something went wrong.
@@ -7,9 +7,6 @@
1. *`rootEpic: Epic`*: The root [Epic](../basics/Epics.md)
2. *`[options: Object]`*: The optional configuration. Options:
* *`dependencies`*: If given, it will be injected as the 3rd argument to all epics.
* *`adapter`*: An adapter object which can transform the input / output streams provided to your epics. Usually used to adapt a stream library other than RxJS v5, like [adapter-rxjs-v4](https://github.com/redux-observable/redux-observable-adapter-rxjs-v4) or [adapter-most](https://github.com/redux-observable/redux-observable-adapter-most) Options:
* *`input: ActionsObservable => any`*: Transforms the input stream of actions, `ActionsObservable` that is passed to your root Epic (transformation takes place *before* it is passed to the root epic).
* *`output: any => Observable`*: Transforms the return value of root Epic (transformation takes place *after* the root epic returned it).
#### Returns
@@ -41,13 +41,7 @@ export interface EpicMiddleware<T extends Action, O extends T = T, S = void, D =
run(rootEpic: Epic<T, O, S, D>): void;
}
interface Adapter {
input: (input$: Observable<any>) => any;
output: (output$: any) => Observable<any>;
}
interface Options<D = any> {
adapter?: Adapter;
dependencies?: D;
}
@@ -3,24 +3,11 @@ import { map, mergeMap, observeOn, subscribeOn } from 'rxjs/operators';
import { ActionsObservable } from './ActionsObservable';
import { StateObservable } from './StateObservable';
const defaultAdapter = {
input: action$ => action$,
output: action$ => action$
};
const defaultOptions = {
adapter: defaultAdapter
};
export function createEpicMiddleware(options = defaultOptions) {
export function createEpicMiddleware(options = {}) {
if (process.env.NODE_ENV !== 'production' && typeof options === 'function') {
throw new TypeError('Providing your root Epic to `createEpicMiddleware(rootEpic)` is no longer supported, instead use `epicMiddleware.run(rootEpic)`\n\nLearn more: https://redux-observable.js.org/MIGRATION.html#setting-up-the-middleware');
}
// even though we used default param, we need to merge the defaults
// inside the options object as well in case they declare only some
options = { ...defaultOptions, ...options };
const epic$ = new Subject();
let store;
@@ -36,9 +23,7 @@ export function createEpicMiddleware(options = defaultOptions) {
const stateSubject$ = new Subject().pipe(
observeOn(queueScheduler)
);
const action$ = options.adapter.input(
new ActionsObservable(actionSubject$)
);
const action$ = new ActionsObservable(actionSubject$);
const state$ = new StateObservable(stateSubject$, store.getState());
const result$ = epic$.pipe(
@@ -54,7 +39,7 @@ export function createEpicMiddleware(options = defaultOptions) {
return output$;
}),
mergeMap(output$ =>
from(options.adapter.output(output$)).pipe(
from(output$).pipe(
subscribeOn(queueScheduler),
observeOn(queueScheduler)
)
@@ -335,26 +335,6 @@ describe('createEpicMiddleware', () => {
});
});
it('supports an adapter for Epic input/output', () => {
const reducer = (state = [], action) => state.concat(action);
const epic = input => input + 1;
const adapter = {
input: () => 1,
output: value => of({
type: value + 1
})
};
const middleware = createEpicMiddleware({ adapter });
const store = createStore(reducer, applyMiddleware(middleware));
middleware.run(epic);
expect(store.getState()).to.deep.equal([
initAction,
{ type: 3 }
]);
});
it('should not pass third argument to epic if no dependencies provided', () => {
const reducer = (state = [], action) => state;
const epic = spySandbox.spy(action$ => action$);

0 comments on commit 87a5f86

Please sign in to comment.