Skip to content

Commit 77fc979

Browse files
committed
Merge branch '4.0.1'
2 parents 54cfea0 + 563992b commit 77fc979

File tree

8 files changed

+153
-33
lines changed

8 files changed

+153
-33
lines changed

README.md

+18-16
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,13 @@ Or [yarn](https://yarnpkg.com/):
3737

3838
```js
3939
// store/configure-store.js
40-
import { applyMiddleware, compose, createStore, combineReducers } from 'redux'
40+
import { createStore, applyMiddleware, combineReducers } from 'redux'
4141
import { createRouterMiddleware, initialRouterState, routerReducer } from 'connected-next-router'
42-
import { format } from 'url'
43-
import { createWrapper, HYDRATE } from 'next-redux-wrapper'
42+
import { HYDRATE, createWrapper } from 'next-redux-wrapper'
4443
import Router from 'next/router'
4544

4645
const rootReducer = combineReducers({
47-
...reducers,
46+
// Add other reducers
4847
router: routerReducer
4948
});
5049

@@ -53,9 +52,13 @@ const routerMiddleware = createRouterMiddleware();
5352
// Using next-redux-wrapper's initStore
5453
const reducer = (state, action) => {
5554
if (action.type === HYDRATE) {
56-
const nextState = { ...state, ...action.payload }
57-
if (typeof window !== 'undefined') {
58-
nextState.router = state.router
55+
const nextState = {
56+
...state, // use previous state
57+
...action.payload, // apply delta from hydration
58+
}
59+
if (typeof window !== 'undefined' && state?.router) {
60+
// preserve router value on client side navigation
61+
nextState.router = state.router
5962
}
6063
return nextState
6164
} else {
@@ -65,12 +68,11 @@ const reducer = (state, action) => {
6568

6669
export const initStore = (context) => {
6770
const routerMiddleware = createRouterMiddleware()
68-
const { asPath, pathname, query } = context.ctx || Router.router || {};
71+
const { asPath } = context.ctx || Router.router || {}
6972
let initialState
7073
if (asPath) {
71-
const url = format({ pathname, query })
7274
initialState = {
73-
router: initialRouterState(url, asPath)
75+
router: initialRouterState(asPath)
7476
}
7577
}
7678
return createStore(reducer, initialState, applyMiddleware(routerMiddleware))
@@ -85,23 +87,23 @@ export const wrapper = createWrapper(initStore)
8587
8688
```js
8789
// pages/_app.js
88-
import App from 'next/app';
90+
import App from 'next/app'
8991
import { ConnectedRouter } from 'connected-next-router'
9092
import { wrapper } from '../store/configure-store'
9193

92-
class MyApp extends App {
94+
class ExampleApp extends App {
9395
render() {
94-
const { Component, pageProps } = this.props;
96+
const { Component, pageProps } = this.props
9597
return (
9698
<ConnectedRouter>
97-
<Component { ...pageProps } />
99+
<Component {...pageProps} />
98100
</ConnectedRouter>
99-
);
101+
)
100102
}
101103
}
102104

103105
// wrapper.withRedux wraps the App with react-redux's Provider
104-
export default wrapper.withRedux(MyApp);
106+
export default wrapper.withRedux(ExampleApp)
105107
```
106108
107109
## Examples

cypress/integration/router.spec.js

+110-7
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,126 @@ describe('Connected Next Router', () => {
1414
cy.visit('/');
1515
});
1616

17-
it('Push route with Redux action', () => {
17+
it('Push route (with query) with Redux action', () => {
1818
cy.contains('Push /about with Redux action').click();
19-
cy.location('pathname').should('include', '/about');
19+
cy.location('pathname').should('equal', '/about');
20+
cy.location('search').should('equal', '?foo=bar')
21+
cy.window()
22+
.then((window) => window.reduxStore.getState().router)
23+
.should('deep.equal', {
24+
location: {
25+
href: '/about?foo=bar',
26+
pathname: '/about',
27+
search: '?foo=bar',
28+
hash: ''
29+
}
30+
});
31+
});
32+
33+
it('Push route (with hash) with Redux action', () => {
34+
cy.contains('Push /#foo with Redux action').click();
35+
cy.location('pathname').should('equal', '/');
36+
cy.location('hash').should('equal', '#foo')
37+
cy.window()
38+
.then((window) => window.reduxStore.getState().router)
39+
.should('deep.equal', {
40+
location: {
41+
href: '/#foo',
42+
pathname: '/',
43+
search: '',
44+
hash: '#foo'
45+
}
46+
});
2047
});
2148

2249
it('Replace route with Redux action', () => {
2350
cy.contains('Replace /blog/2 with Redux action').click();
24-
cy.location('pathname').should('include', '/blog/2');
51+
cy.location('pathname').should('equal', '/blog/2');
52+
cy.window()
53+
.then((window) => window.reduxStore.getState().router)
54+
.should('deep.equal', {
55+
location: {
56+
href: '/blog/2',
57+
pathname: '/blog/2',
58+
search: '',
59+
hash: ''
60+
}
61+
});
62+
2563
cy.contains('Replace / with Redux action').click();
2664
cy.location('pathname').should('equal', '/');
65+
cy.window()
66+
.then((window) => window.reduxStore.getState().router)
67+
.should('deep.equal', {
68+
location: {
69+
href: '/',
70+
pathname: '/',
71+
search: '',
72+
hash: ''
73+
}
74+
});
2775
});
2876

2977
it('Go back with Redux action', () => {
3078
cy.contains('Push /about with Redux action').click();
31-
cy.location('pathname').should('include', '/about');
79+
cy.location('pathname').should('equal', '/about');
80+
cy.location('search').should('equal', '?foo=bar')
81+
cy.window()
82+
.then((window) => window.reduxStore.getState().router)
83+
.should('deep.equal', {
84+
location: {
85+
href: '/about?foo=bar',
86+
pathname: '/about',
87+
search: '?foo=bar',
88+
hash: ''
89+
}
90+
});
91+
3292
cy.contains('Go Back with Redux action').click();
3393
cy.location('pathname').should('equal', '/');
94+
cy.window()
95+
.then((window) => window.reduxStore.getState().router)
96+
.should('deep.equal', {
97+
location: {
98+
href: '/',
99+
pathname: '/',
100+
search: '',
101+
hash: ''
102+
}
103+
});
34104
});
35105

36106
it('Go forward with Redux action', () => {
37107
cy.contains('Push /about with Redux action').click();
38-
cy.location('pathname').should('include', '/about');
108+
cy.location('pathname').should('equal', '/about');
109+
cy.location('search').should('equal', '?foo=bar')
110+
cy.window()
111+
.then((window) => window.reduxStore.getState().router)
112+
.should('deep.equal', {
113+
location: {
114+
href: '/about?foo=bar',
115+
pathname: '/about',
116+
search: '?foo=bar',
117+
hash: ''
118+
}
119+
});
120+
39121
cy.go('back');
40122
cy.location('pathname').should('equal', '/');
123+
41124
cy.contains('Go Forward with Redux action').click();
42-
cy.location('pathname').should('include', '/about');
125+
cy.location('pathname').should('equals', '/about');
126+
cy.location('search').should('equal', '?foo=bar')
127+
cy.window()
128+
.then((window) => window.reduxStore.getState().router)
129+
.should('deep.equal', {
130+
location: {
131+
href: '/about?foo=bar',
132+
pathname: '/about',
133+
search: '?foo=bar',
134+
hash: ''
135+
}
136+
});
43137
});
44138

45139
it('Prefetch with Redux action', () => {
@@ -52,9 +146,18 @@ describe('Connected Next Router', () => {
52146
});
53147

54148
it('Ignores invalid URLs passed to the action', () => {
55-
cy.visit('/');
56149
cy.contains('Push empty url').click();
57150
cy.location('pathname').should('equal', '/');
151+
cy.window()
152+
.then((window) => window.reduxStore.getState().router)
153+
.should('deep.equal', {
154+
location: {
155+
href: '/',
156+
pathname: '/',
157+
search: '',
158+
hash: ''
159+
}
160+
});
58161
});
59162
});
60163

e2e/components/navigation.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ const Navigation = () => {
2525
Push /about with Redux action
2626
</a>
2727
</li>
28+
<li>
29+
<a
30+
href="/#foo"
31+
onClick={e => {
32+
e.preventDefault()
33+
dispatch(push('/', '/#foo'))
34+
}}
35+
>
36+
Push /#foo with Redux action
37+
</a>
38+
</li>
2839
<li>
2940
<a
3041
href="/blog/2"

examples/basic/store/configure-store.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const reducer = (state, action) => {
2020
}
2121
if (typeof window !== 'undefined' && state?.router) {
2222
// preserve router value on client side navigation
23-
nextState.router = state.router
23+
nextState.router = state.router
2424
}
2525
return nextState
2626
} else {
@@ -30,7 +30,7 @@ const reducer = (state, action) => {
3030

3131
export const initStore = (context) => {
3232
const routerMiddleware = createRouterMiddleware()
33-
const { asPath } = context.ctx || Router.router || {};
33+
const { asPath } = context.ctx || Router.router || {}
3434
let initialState
3535
if (asPath) {
3636
initialState = {
@@ -40,4 +40,4 @@ export const initStore = (context) => {
4040
return createStore(reducer, initialState, bindMiddleware([routerMiddleware]))
4141
}
4242

43-
export const wrapper = createWrapper(initStore)
43+
export const wrapper = createWrapper(initStore)

examples/typescript/store/configure-store.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const reducer: Reducer<State, AnyAction> = (state, action) => {
2323
}
2424
if (typeof window !== 'undefined' && state?.router) {
2525
// preserve router value on client side navigation
26-
nextState.router = state.router
26+
nextState.router = state.router
2727
}
2828
return nextState
2929
} else {
@@ -33,7 +33,7 @@ const reducer: Reducer<State, AnyAction> = (state, action) => {
3333

3434
export const initStore: MakeStore<State> = (context) => {
3535
const routerMiddleware = createRouterMiddleware()
36-
const { asPath } = (context as AppContext).ctx || Router.router || {};
36+
const { asPath } = (context as AppContext).ctx || Router.router || {}
3737
let initialState
3838
if (asPath) {
3939
initialState = {
@@ -43,4 +43,4 @@ export const initStore: MakeStore<State> = (context) => {
4343
return createStore(reducer, initialState, bindMiddleware([routerMiddleware]))
4444
}
4545

46-
export const wrapper = createWrapper(initStore)
46+
export const wrapper = createWrapper(initStore)

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "connected-next-router",
3-
"version": "4.0.0",
3+
"version": "4.0.1",
44
"description": "A Redux binding for Next.js Router",
55
"author": "Daniel Reinoso <[email protected]> (http://danielr18.github.io)",
66
"license": "MIT",

src/ConnectedRouter.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,19 @@ const createConnectedRouter = (structure: Structure): React.FC<ConnectedRouterPr
9595
// @ts-ignore
9696
unpatchRouter = patchRouter(Router, store)
9797
Router.events.on('routeChangeStart', trackRouteStart)
98-
Router.events.on('routeChangeError', onRouteChangeFinish)
98+
Router.events.on('routeChangeError', trackRouteComplete)
9999
Router.events.on('routeChangeComplete', onRouteChangeFinish)
100+
Router.events.on('hashChangeStart', trackRouteStart)
101+
Router.events.on('hashChangeComplete', onRouteChangeFinish)
100102
})
101103

102104
return () => {
103105
unpatchRouter()
104106
Router.events.off('routeChangeStart', trackRouteStart)
105-
Router.events.off('routeChangeError', onRouteChangeFinish)
107+
Router.events.off('routeChangeError', trackRouteComplete)
106108
Router.events.off('routeChangeComplete', onRouteChangeFinish)
109+
Router.events.off('hashChangeStart', trackRouteStart)
110+
Router.events.off('hashChangeComplete', onRouteChangeFinish)
107111
}
108112
}, [Router, reducerKey, store])
109113

src/middleware.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const createRouterMiddleware = (structure: Structure) => (middlewareOpts: Router
5959
throw new Error(`Router method "${method}" for ${payloadMethod} action does not exist`)
6060
}
6161
} else {
62-
next(action)
62+
return next(action)
6363
}
6464
}
6565
}

0 commit comments

Comments
 (0)