Skip to content

Commit

Permalink
feat(adapters): remove adapters support
Browse files Browse the repository at this point in the history
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 87a5f86
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 100 deletions.
33 changes: 33 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
19 changes: 0 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
34 changes: 0 additions & 34 deletions docs/FAQ.md

This file was deleted.

3 changes: 0 additions & 3 deletions docs/api/createEpicMiddleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 0 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
21 changes: 3 additions & 18 deletions src/createEpicMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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(
Expand All @@ -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)
)
Expand Down
20 changes: 0 additions & 20 deletions test/createEpicMiddleware-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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$);
Expand Down

0 comments on commit 87a5f86

Please sign in to comment.