diff --git a/src/createStore.js b/src/createStore.js index e104d68735..c062d62388 100644 --- a/src/createStore.js +++ b/src/createStore.js @@ -39,6 +39,7 @@ export default function createStore(reducer, initialState) { var currentState = initialState; var listeners = []; var isDispatching = false; + var inTransaction = false; /** * Reads the state tree managed by the store. @@ -117,10 +118,42 @@ export default function createStore(reducer, initialState) { isDispatching = false; } - listeners.slice().forEach(listener => listener()); + if (!inTransaction) { + listeners.slice().forEach(listener => listener()); + } return action; } + /** + * Start transaction + * + * No one listeners will be called until commit() transaction. + * + * @return {void} + */ + function begin() { + if (inTransaction) { + throw new Error( + 'Only one transaction may be started with begin() call.' + ); + } + inTransaction = true; + } + + /** + * Commit + * @return {void} + */ + function commit() { + if (!inTransaction) { + throw new Error( + 'You must call begin() before commit().' + ); + } + inTransaction = false; + listeners.slice().forEach(listener => listener()); + } + /** * Replaces the reducer currently used by the store to calculate the state. * @@ -142,6 +175,8 @@ export default function createStore(reducer, initialState) { dispatch({ type: ActionTypes.INIT }); return { + begin, + commit, dispatch, subscribe, getState, diff --git a/test/createStore.spec.js b/test/createStore.spec.js index 5a19a63299..4705283f11 100644 --- a/test/createStore.spec.js +++ b/test/createStore.spec.js @@ -8,11 +8,13 @@ describe('createStore', () => { const store = createStore(combineReducers(reducers)); const methods = Object.keys(store); - expect(methods.length).toBe(4); + expect(methods.length).toBe(6); expect(methods).toContain('subscribe'); expect(methods).toContain('dispatch'); expect(methods).toContain('getState'); expect(methods).toContain('replaceReducer'); + expect(methods).toContain('begin'); + expect(methods).toContain('commit'); }); it('should require a reducer function', () => { @@ -321,4 +323,23 @@ describe('createStore', () => { store.dispatch({ type: '' }) ).toNotThrow(); }); + + it('should not call listeners if begin() called', () => { + const store = createStore(reducers.todos); + let called = false; + store.subscribe(() => { + called = true; + }); + + store.dispatch({type: 'test'}); + expect(called).toBe(true); + called = false; + + store.begin(); + store.dispatch({type: 'test'}); + expect(called).toBe(false); + + store.commit(); + expect(called).toBe(true); + }); });