From bb05510684c78f86a269153c0c1f1b26474f101c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Gr=C3=B6nlund?= Date: Tue, 26 Jan 2016 23:41:31 +0100 Subject: [PATCH] Fix #24 where DragDropMonitor failes to notify subscribeToStateChange subscribers in some cases --- src/DragDropMonitor.js | 16 ++++++++++++++-- src/reducers/index.js | 4 +++- src/reducers/stateId.js | 3 +++ test/DragDropMonitor.spec.js | 23 +++++++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/reducers/stateId.js diff --git a/src/DragDropMonitor.js b/src/DragDropMonitor.js index bddf9ab..6810e2a 100644 --- a/src/DragDropMonitor.js +++ b/src/DragDropMonitor.js @@ -23,9 +23,21 @@ export default class DragDropMonitor { 'handlerIds, when specified, must be an array of strings.' ); + let prevStateId = this.store.getState().stateId; const handleChange = () => { - if (areDirty(this.store.getState().dirtyHandlerIds, handlerIds)) { - listener(); + const state = this.store.getState(); + const currentStateId = state.stateId; + try { + const canSkipListener = currentStateId === prevStateId || ( + currentStateId === prevStateId + 1 && + !areDirty(state.dirtyHandlerIds, handlerIds) + ) + + if (!canSkipListener) { + listener(); + } + } finally { + prevStateId = currentStateId; } }; diff --git a/src/reducers/index.js b/src/reducers/index.js index 52369a6..1e194b7 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -2,12 +2,14 @@ import { default as dragOffset } from './dragOffset'; import { default as dragOperation } from './dragOperation'; import { default as refCount } from './refCount'; import { default as dirtyHandlerIds } from './dirtyHandlerIds'; +import { default as stateId } from './stateId'; export default function (state = {}, action) { return { dirtyHandlerIds: dirtyHandlerIds(state.dirtyHandlerIds, action, state.dragOperation), dragOffset: dragOffset(state.dragOffset, action), refCount: refCount(state.refCount, action), - dragOperation: dragOperation(state.dragOperation, action) + dragOperation: dragOperation(state.dragOperation, action), + stateId: stateId(state.stateId) }; } \ No newline at end of file diff --git a/src/reducers/stateId.js b/src/reducers/stateId.js new file mode 100644 index 0000000..dea1373 --- /dev/null +++ b/src/reducers/stateId.js @@ -0,0 +1,3 @@ +export default function stateId(state = 0) { + return state + 1; +} diff --git a/test/DragDropMonitor.spec.js b/test/DragDropMonitor.spec.js index 5c44bf2..a549691 100644 --- a/test/DragDropMonitor.spec.js +++ b/test/DragDropMonitor.spec.js @@ -463,6 +463,29 @@ describe('DragDropMonitor', () => { expect(raisedChange).to.equal(false); }); + it('raises global change event on beginDrag(), even if redux did not notify us for all stat updates.', (done) => { + const source = new NormalSource(); + const sourceId = registry.addSource(Types.FOO, source); + const target = new NormalTarget() + + let notified = false; + monitor.subscribeToStateChange( + () => { + if (!notified) + { + notified = true; + // Add target will send an action to redux, which will trigger a new state update. + // The redux behaviour then is to send only the latest state to the subscribers + // which means that the subscription below will not receive this state. + registry.addTarget(Types.FOO, target) + } + }); + + monitor.subscribeToStateChange( + () => { done()}); + backend.simulateBeginDrag([sourceId]); + }); + it('throws when passing clientOffset without getSourceClientOffset', () => { const source = new NormalSource(); const sourceId = registry.addSource(Types.FOO, source);