Skip to content

Commit

Permalink
Prevent double-rendering on initilization (supasate#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmarfany committed Apr 30, 2019
1 parent 4bf3c51 commit d442129
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/actions.js
Expand Up @@ -4,11 +4,12 @@
*/
export const LOCATION_CHANGE = '@@router/LOCATION_CHANGE'

export const onLocationChanged = (location, action) => ({
export const onLocationChanged = (location, action, isFirstRendering = false) => ({
type: LOCATION_CHANGE,
payload: {
location,
action,
isFirstRendering,
}
})

Expand Down
7 changes: 6 additions & 1 deletion src/reducer.js
Expand Up @@ -18,7 +18,12 @@ const createConnectRouter = (structure) => {
*/
return (state = initialRouterState, { type, payload } = {}) => {
if (type === LOCATION_CHANGE) {
return merge(state, payload)
const { location, action, isFirstRendering } = payload
// Don't update the state ref for the first rendering
// to prevent the double-rendering issue on initialization
return isFirstRendering
? state
: merge(state, { location, action })
}

return state
Expand Down
18 changes: 18 additions & 0 deletions test/actions.test.js
Expand Up @@ -21,6 +21,24 @@ describe('Actions', () => {
hash: '',
},
action: 'POP',
isFirstRendering: false,
},
}
expect(actualAction).toEqual(expectedAction)
})

it('returns correct action when calling onLocationChanged() for the first rendering', () => {
const actualAction = onLocationChanged({ pathname: '/', search: '', hash: '' }, 'POP', true)
const expectedAction = {
type: LOCATION_CHANGE,
payload: {
location: {
pathname: '/',
search: '',
hash: '',
},
action: 'POP',
isFirstRendering: true,
},
}
expect(actualAction).toEqual(expectedAction)
Expand Down
92 changes: 91 additions & 1 deletion test/reducer.test.js
Expand Up @@ -92,6 +92,36 @@ describe('connectRouter', () => {
const nextState = rootReducer(currentState, action)
expect(nextState).toBe(currentState)
})

it('does not change state ref when receiving LOCATION_CHANGE for the first rendering', () => {
const rootReducer = combineReducers({
router: connectRouter(mockHistory)
})
const currentState = {
router: {
location: {
pathname: '/',
search: '',
hash: '',
},
action: 'POP',
},
}
const action = {
type: LOCATION_CHANGE,
payload: {
location: {
pathname: '/',
search: '',
hash: '',
},
action: 'POP',
isFirstRendering: true,
}
}
const nextState = rootReducer(currentState, action)
expect(nextState).toBe(currentState)
})
})

describe('with immutable structure', () => {
Expand Down Expand Up @@ -143,6 +173,36 @@ describe('connectRouter', () => {
})
expect(nextState).toEqual(expectedState)
})

it('does not change state ref when receiving LOCATION_CHANGE for the first rendering', () => {
const rootReducer = combineReducers({
router: connectRouter(mockHistory)
})
const currentState = {
router: {
location: {
pathname: '/',
search: '',
hash: '',
},
action: 'POP',
},
}
const action = {
type: LOCATION_CHANGE,
payload: {
location: {
pathname: '/',
search: '',
hash: '',
},
action: 'POP',
isFirstRendering: true,
}
}
const nextState = rootReducer(currentState, action)
expect(nextState).toBe(currentState)
})
})

describe('with seamless immutable structure', () => {
Expand Down Expand Up @@ -194,5 +254,35 @@ describe('connectRouter', () => {
}
expect(nextState).toEqual(expectedState)
})

it('does not change state ref when receiving LOCATION_CHANGE for the first rendering', () => {
const rootReducer = combineReducers({
router: connectRouter(mockHistory)
})
const currentState = {
router: {
location: {
pathname: '/',
search: '',
hash: '',
},
action: 'POP',
},
}
const action = {
type: LOCATION_CHANGE,
payload: {
location: {
pathname: '/',
search: '',
hash: '',
},
action: 'POP',
isFirstRendering: true,
}
}
const nextState = rootReducer(currentState, action)
expect(nextState).toBe(currentState)
})
})
})
})

0 comments on commit d442129

Please sign in to comment.