Skip to content

Commit b13e8b8

Browse files
committed
Merge pull request acdlite#55 from acdlite/better-server-rendering
Throw if routes not given to enhancer when server rendering
2 parents 7eaf206 + 2cf0135 commit b13e8b8

File tree

5 files changed

+70
-7
lines changed

5 files changed

+70
-7
lines changed

src/__tests__/ReduxRouter-test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,21 @@ describe('<ReduxRouter>', () => {
140140
}));
141141
});
142142

143+
it('throws if routes are not passed to store enhancer', () => {
144+
const reducer = combineReducers({
145+
router: routerStateReducer
146+
});
147+
148+
expect(() => server.reduxReactRouter()(createStore)(reducer))
149+
.to.throw(
150+
'When rendering on the server, routes must be passed to the '
151+
+ 'reduxReactRouter() store enhancer; routes as a prop or as children '
152+
+ 'of <ReduxRouter> is not supported. To deal with circular '
153+
+ 'dependencies between routes and the store, use the '
154+
+ 'option getRoutes(store).'
155+
);
156+
});
157+
143158
it('handles redirects', () => {
144159
const reducer = combineReducers({
145160
router: routerStateReducer

src/__tests__/reduxReactRouter-test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,29 @@ describe('reduxRouter()', () => {
140140
expect(store.getState().string).to.equal('Unidirectional');
141141
});
142142

143+
describe('getRoutes()', () => {
144+
it('is passed dispatch and getState', () => {
145+
const reducer = combineReducers({
146+
router: routerStateReducer
147+
});
148+
149+
let store;
150+
const history = createHistory();
151+
152+
reduxReactRouter({
153+
history,
154+
getRoutes: s => {
155+
store = s;
156+
return routes;
157+
}
158+
})(createStore)(reducer);
159+
160+
store.dispatch(pushState(null, '/parent/child/123', { key: 'value'}));
161+
expect(store.getState().router.location.pathname)
162+
.to.equal('/parent/child/123');
163+
});
164+
});
165+
143166
describe('onEnter hook', () => {
144167
it('can perform redirects', () => {
145168
const reducer = combineReducers({

src/client.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import reduxReactRouter from './reduxReactRouter';
55
import useDefaults from './useDefaults';
66
import routeReplacement from './routeReplacement';
77

8-
function client(next) {
8+
function historySynchronization(next) {
99
return options => createStore => (reducer, initialState) => {
1010
const { onError, routerStateSelector } = options;
1111
const store = next(options)(createStore)(reducer, initialState);
@@ -47,5 +47,5 @@ function client(next) {
4747
export default compose(
4848
useDefaults,
4949
routeReplacement,
50-
client
50+
historySynchronization
5151
)(reduxReactRouter);

src/routeReplacement.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default function routeReplacement(next) {
66
return options => createStore => (reducer, initialState) => {
77
const {
88
routes: baseRoutes,
9+
getRoutes,
910
routerStateSelector
1011
} = options;
1112

@@ -30,9 +31,16 @@ export default function routeReplacement(next) {
3031
}
3132
}
3233

33-
const routes = baseRoutes
34-
? baseRoutes
35-
: [{
34+
let routes;
35+
if (baseRoutes) {
36+
routes = baseRoutes;
37+
} else if (getRoutes) {
38+
routes = getRoutes({
39+
dispatch: action => store.dispatch(action),
40+
getState: () => store.getState()
41+
});
42+
} else {
43+
routes = [{
3644
getChildRoutes: (location, cb) => {
3745
if (!areChildRoutesResolved) {
3846
childRoutesCallbacks.push(cb);
@@ -42,6 +50,7 @@ export default function routeReplacement(next) {
4250
cb(null, childRoutes);
4351
}
4452
}];
53+
}
4554

4655
store = compose(
4756
applyMiddleware(

src/server.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,22 @@ import routeReplacement from './routeReplacement';
66
import matchMiddleware from './matchMiddleware';
77
import { MATCH } from './constants';
88

9-
function server(next) {
9+
function serverInvariants(next) {
10+
return options => createStore => {
11+
if (!options || !(options.routes || options.getRoutes)) {
12+
throw new Error(
13+
'When rendering on the server, routes must be passed to the '
14+
+ 'reduxReactRouter() store enhancer; routes as a prop or as children of '
15+
+ '<ReduxRouter> is not supported. To deal with circular dependencies '
16+
+ 'between routes and the store, use the option getRoutes(store).'
17+
);
18+
}
19+
20+
return next(options)(createStore);
21+
};
22+
}
23+
24+
function matching(next) {
1025
return options => createStore => (reducer, initialState) => {
1126
const store = compose(
1227
applyMiddleware(
@@ -32,7 +47,8 @@ export function match(url, callback) {
3247
}
3348

3449
export const reduxReactRouter = compose(
50+
serverInvariants,
3551
useDefaults,
3652
routeReplacement,
37-
server
53+
matching
3854
)(baseReduxReactRouter);

0 commit comments

Comments
 (0)