Skip to content
This repository was archived by the owner on Oct 26, 2018. It is now read-only.

Commit 6f3aa01

Browse files
committed
Merge pull request #73 from kjbekkelund/dev-tools-fix
Get devtools working
2 parents 211e9cd + ab7b481 commit 6f3aa01

File tree

3 files changed

+109
-9
lines changed

3 files changed

+109
-9
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"karma-webpack": "^1.7.0",
5454
"mocha": "^2.3.4",
5555
"redux": "^3.0.4",
56+
"redux-devtools": "^2.1.5",
5657
"webpack": "^1.12.9"
5758
},
5859
"dependencies": {

src/index.js

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,26 @@ function update(state=initialState, { type, payload }) {
5555
// Syncing
5656

5757
function locationsAreEqual(a, b) {
58-
return a.path === b.path && deepEqual(a.state, b.state);
58+
return a != null && b != null && a.path === b.path && deepEqual(a.state, b.state);
5959
}
6060

6161
function syncReduxAndRouter(history, store, selectRouterState = SELECT_STATE) {
6262
const getRouterState = () => selectRouterState(store.getState());
63-
let lastChangeId = 0;
63+
64+
// Because we're not able to set the initial path in `initialState` we need a
65+
// "hack" to get "Revert" in Redux DevTools to work. We solve this by keeping
66+
// the first route so we can revert to this route when the initial state is
67+
// replayed to reset the state. Basically, we treat the first route as our
68+
// initial state.
69+
let firstRoute = undefined;
70+
71+
// To properly handle store updates we need to track the last route. This
72+
// route contains a `changeId` which is updated on every `pushPath` and
73+
// `replacePath`. If this id changes we always trigger a history update.
74+
// However, if the id does not change, we check if the location has changed,
75+
// and if it is we trigger a history update. (If these are out of sync it's
76+
// likely because of React DevTools.)
77+
let lastRoute = undefined;
6478

6579
if(!getRouterState()) {
6680
throw new Error(
@@ -75,6 +89,10 @@ function syncReduxAndRouter(history, store, selectRouterState = SELECT_STATE) {
7589
state: location.state
7690
};
7791

92+
if (firstRoute === undefined) {
93+
firstRoute = route;
94+
}
95+
7896
// Avoid dispatching an action if the store is already up-to-date,
7997
// even if `history` wouldn't do anything if the location is the same
8098
if(locationsAreEqual(getRouterState(), route)) return;
@@ -87,14 +105,22 @@ function syncReduxAndRouter(history, store, selectRouterState = SELECT_STATE) {
87105
});
88106

89107
const unsubscribeStore = store.subscribe(() => {
90-
const routing = getRouterState();
108+
let routing = getRouterState();
91109

92-
// Only update the router once per `pushPath` call. This is
93-
// indicated by the `changeId` state; when that number changes, we
94-
// should update the history.
95-
if(lastChangeId === routing.changeId) return;
110+
// Treat `firstRoute` as our `initialState`
111+
if(routing === initialState) {
112+
routing = firstRoute;
113+
}
114+
115+
// Only trigger history update is this is a new change or the location
116+
// has changed.
117+
if(lastRoute !== undefined &&
118+
lastRoute.changeId === routing.changeId &&
119+
locationsAreEqual(lastRoute, routing)) {
120+
return;
121+
}
96122

97-
lastChangeId = routing.changeId;
123+
lastRoute = routing;
98124

99125
const method = routing.replace ? 'replaceState' : 'pushState';
100126

test/createTests.js

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const expect = require('expect');
22
const { pushPath, replacePath, UPDATE_PATH, routeReducer, syncReduxAndRouter } = require('../src/index');
3-
const { createStore, combineReducers } = require('redux');
3+
const { createStore, combineReducers, compose } = require('redux');
4+
const { devTools } = require('redux-devtools');
5+
const { ActionCreators } = require('redux-devtools/lib/devTools');
46

57
expect.extend({
68
toContainRoute({
@@ -149,6 +151,77 @@ module.exports = function createTests(createHistory, name, reset = defaultReset)
149151
});
150152
});
151153

154+
describe('devtools', () => {
155+
let history, store, devToolsStore, unsubscribe;
156+
157+
beforeEach(() => {
158+
history = createHistory();
159+
const finalCreateStore = compose(devTools())(createStore);
160+
store = finalCreateStore(combineReducers({
161+
routing: routeReducer
162+
}));
163+
devToolsStore = store.devToolsStore;
164+
165+
// Set initial URL before syncing
166+
history.pushState(null, '/foo');
167+
168+
unsubscribe = syncReduxAndRouter(history, store);
169+
});
170+
171+
afterEach(() => {
172+
unsubscribe();
173+
});
174+
175+
it('resets to the initial url', () => {
176+
let lastPath;
177+
const historyUnsubscribe = history.listen(location => {
178+
lastPath = location.pathname;
179+
});
180+
181+
history.pushState(null, '/bar');
182+
store.dispatch(pushPath('/baz'));
183+
184+
devToolsStore.dispatch(ActionCreators.reset());
185+
186+
expect(store.getState().routing.path).toEqual('/foo');
187+
expect(lastPath).toEqual('/foo');
188+
});
189+
190+
it('handles toggle after store change', () => {
191+
let lastPath;
192+
const historyUnsubscribe = history.listen(location => {
193+
lastPath = location.pathname;
194+
});
195+
196+
// action 2
197+
history.pushState(null, '/foo2');
198+
// action 3
199+
history.pushState(null, '/foo3');
200+
201+
devToolsStore.dispatch(ActionCreators.toggleAction(3));
202+
expect(lastPath).toEqual('/foo2');
203+
204+
historyUnsubscribe();
205+
});
206+
207+
it('handles toggle after store change', () => {
208+
let lastPath;
209+
const historyUnsubscribe = history.listen(location => {
210+
lastPath = location.pathname;
211+
});
212+
213+
// action 2
214+
store.dispatch(pushPath('/foo2'));
215+
// action 3
216+
store.dispatch(pushPath('/foo3'));
217+
218+
devToolsStore.dispatch(ActionCreators.toggleAction(3));
219+
expect(lastPath).toEqual('/foo2');
220+
221+
historyUnsubscribe();
222+
});
223+
});
224+
152225
describe('syncReduxAndRouter', () => {
153226
let history, store, unsubscribe;
154227

0 commit comments

Comments
 (0)