From 7b5adf9718560c3ab852889fcdbf1ec8d87c7fa4 Mon Sep 17 00:00:00 2001 From: Michael van Engelshoven Date: Mon, 9 May 2016 03:45:26 +0200 Subject: [PATCH] Fix redux support for observables (#275) fixes #274 --- package.json | 6 ++++-- src/instrument.js | 38 +++++++++++++++++++++++++++++++------- test/instrument.spec.js | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 89c3395341..7eccfa536d 100644 --- a/package.json +++ b/package.json @@ -54,15 +54,17 @@ "react-addons-test-utils": "^0.14.0", "react-dom": "^0.14.0", "rimraf": "^2.3.4", + "rxjs": "^5.0.0-beta.6", "webpack": "^1.11.0" }, "peerDependencies": { - "redux": "^3.0.0", + "redux": "^3.5.0", "react": "^0.14.0 || ^15.0.0-rc.1" }, "dependencies": { "lodash": "^4.2.0", "react-redux": "^4.0.0", - "redux": "^3.2.1" + "redux": "^3.5.2", + "symbol-observable": "^0.2.4" } } diff --git a/src/instrument.js b/src/instrument.js index 7ff63a2fef..feabdd0132 100644 --- a/src/instrument.js +++ b/src/instrument.js @@ -1,5 +1,6 @@ import difference from 'lodash/difference'; import union from 'lodash/union'; +import $$observable from 'symbol-observable'; export const ActionTypes = { PERFORM_ACTION: 'PERFORM_ACTION', @@ -383,6 +384,14 @@ function unliftState(liftedState) { function unliftStore(liftedStore, liftReducer) { let lastDefinedState; + function getState() { + const state = unliftState(liftedStore.getState()); + if (state !== undefined) { + lastDefinedState = state; + } + return lastDefinedState; + } + return { ...liftedStore, @@ -393,16 +402,31 @@ function unliftStore(liftedStore, liftReducer) { return action; }, - getState() { - const state = unliftState(liftedStore.getState()); - if (state !== undefined) { - lastDefinedState = state; - } - return lastDefinedState; - }, + getState, replaceReducer(nextReducer) { liftedStore.replaceReducer(liftReducer(nextReducer)); + }, + + [$$observable]() { + return { + ...liftedStore[$$observable](), + subscribe(observer) { + if (typeof observer !== 'object') { + throw new TypeError('Expected the observer to be an object.'); + } + + function observeState() { + if (observer.next) { + observer.next(getState()); + } + } + + observeState(); + const unsubscribe = liftedStore.subscribe(observeState); + return { unsubscribe }; + } + }; } }; } diff --git a/test/instrument.spec.js b/test/instrument.spec.js index bc8bfd24df..a955715582 100644 --- a/test/instrument.spec.js +++ b/test/instrument.spec.js @@ -1,6 +1,9 @@ import expect, { spyOn } from 'expect'; import { createStore, compose } from 'redux'; import instrument, { ActionCreators } from '../src/instrument'; +import {Observable} from 'rxjs'; + +import 'rxjs/add/observable/from'; function counter(state = 0, action) { switch (action.type) { @@ -53,6 +56,21 @@ describe('instrument', () => { expect(store.getState()).toBe(2); }); + it('should provide observable', () => { + let lastValue; + let calls = 0; + + Observable.from(store) + .subscribe(state => { + lastValue = state; + calls++; + }); + + expect(lastValue).toBe(0); + store.dispatch({ type: 'INCREMENT' }); + expect(lastValue).toBe(1); + }); + it('should rollback state to the last committed state', () => { store.dispatch({ type: 'INCREMENT' }); store.dispatch({ type: 'INCREMENT' });