From 8fbfa22f89496590e8b286991ab7e9d83449a53f 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 https://github.com/gaearon/redux-devtools/pull/275 --- package.json | 9 ++++++--- src/instrument.js | 38 +++++++++++++++++++++++++++++++------- test/instrument.spec.js | 18 ++++++++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index a9e411b..3e94730 100644 --- a/package.json +++ b/package.json @@ -47,10 +47,13 @@ "expect": "^1.6.0", "isparta": "^3.0.3", "mocha": "^2.2.5", - "redux": "^3.0.0", - "rimraf": "^2.3.4" + "redux": "^3.5.2", + "rimraf": "^2.3.4", + "rxjs": "^5.0.0-beta.6", + "webpack": "^1.11.0" }, "dependencies": { - "lodash": "^4.2.0" + "lodash": "^4.2.0", + "symbol-observable": "^0.2.4" } } diff --git a/src/instrument.js b/src/instrument.js index dfd86b6..797abf3 100644 --- a/src/instrument.js +++ b/src/instrument.js @@ -1,6 +1,7 @@ import difference from 'lodash/difference'; import union from 'lodash/union'; import isPlainObject from 'lodash/isPlainObject'; +import $$observable from 'symbol-observable'; export const ActionTypes = { PERFORM_ACTION: 'PERFORM_ACTION', @@ -392,6 +393,14 @@ export function unliftState(liftedState) { export function unliftStore(liftedStore, liftReducer) { let lastDefinedState; + function getState() { + const state = unliftState(liftedStore.getState()); + if (state !== undefined) { + lastDefinedState = state; + } + return lastDefinedState; + } + return { ...liftedStore, @@ -402,16 +411,31 @@ export 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 9949e28..8e973b5 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' });