Skip to content
This repository has been archived by the owner on Dec 15, 2018. It is now read-only.

From router.enhancer to router.connect #216

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions ADVANCED.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,18 @@ app.use('/*', (req, res) => {
// routerForExpress will infer the basename
// from req.baseUrl!
//
const { reducer, middleware, enhancer } = routerForExpress({
const { reducer, middleware, connect } = routerForExpress({
routes,
request: req
})

const store = createStore(
combineReducers({ router: reducer }),
{ what: 'ever' },
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);

connect(store);

// ...then renderToString() your components as usual,
// passing your new store to your <Provider> component.
Expand Down Expand Up @@ -86,16 +88,18 @@ server.route({
// Create the Redux store, passing in the Hapi
// request to the routerForHapi factory.

const { reducer, middleware, enhancer } = routerForHapi({
const { reducer, middleware, connect } = routerForHapi({
routes,
request
})

const store = createStore(
reducer,
{ what: 'ever' },
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);

connect(store);

// ...then renderToString() your components as usual,
// passing your new store to your <Provider> component.
Expand Down Expand Up @@ -125,16 +129,18 @@ const routes = {

const {
reducer,
enhancer,
connect,
middleware
} = routerForBrowser({ routes });

const store = createStore(
combineReducers({ router: reducer }),
window.__INITIAL_STATE,
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);

connect(store);

// ...then render() your components as usual,
// passing your new store to your <Provider> component.
```
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ While React Router is a great, well-supported library, it hoards URL state withi

## Redux usage

To hook into Redux applications, `redux-little-router` uses a store enhancer that wraps the `history` module and adds current and previous router state to your store. The enhancer listens for location changes and dispatches rich actions containing the URL, parameters, and any custom data assigned to the route. `redux-little-router` also adds a middleware that intercepts navigation actions and calls their equivalent method in `history`.
To connect into Redux applications, `redux-little-router` uses a store connector that wraps the `history` module and adds current and previous router state to your store. The connector listens for location changes and dispatches rich actions containing the URL, parameters, and any custom data assigned to the route. `redux-little-router` also adds a middleware that intercepts navigation actions and calls their equivalent method in `history`.

### Wiring up the boilerplate

Expand Down Expand Up @@ -72,11 +72,11 @@ const routes = {

// Install the router into the store for a browser-only environment.
// routerForBrowser is a factory method that returns a store
// enhancer and a middleware.
// connect and a middleware.
const {
reducer,
middleware,
enhancer
connect
} = routerForBrowser({
// The configured routes. Required.
routes,
Expand All @@ -87,11 +87,13 @@ const {
const clientOnlyStore = createStore(
combineReducers({ router: reducer, yourReducer }),
initialState,
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);

connect(clientOnlyStore);
```

Often, you'll want to update state or trigger side effects after loading the initial URL. To maintain compatibility with other store enhancers (particularly ones that handle side effects, like `redux-loop` or `redux-saga`), we require this optional initial dispatch to happen in client code by doing the following:
Often, you'll want to update state or trigger side effects after loading the initial URL. To maintain compatibility with store enhancers (particularly ones that handle side effects, like `redux-loop` or `redux-saga`), we require this optional initial dispatch to happen in client code by doing the following:

```js
import { initializeCurrentLocation } from 'redux-little-router';
Expand Down Expand Up @@ -164,7 +166,7 @@ export const redirect = href => dispatch => {
};
```

On location changes, the store enhancer dispatches a `LOCATION_CHANGED` action that contains at least the following properties:
On location changes, the router connector dispatches a `LOCATION_CHANGED` action that contains at least the following properties:

```js
// For a URL matching /messages/:user
Expand Down
5 changes: 2 additions & 3 deletions demo/client/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@ import routes from './routes';
import wrap from './wrap';
import Demo from './demo';

const { reducer, enhancer, middleware } = routerForBrowser({ routes });
const { reducer, connect, middleware } = routerForBrowser({ routes });

const store = createStore(
combineReducers({ router: reducer }),
// If this is a server render, we grab the
// initial state the hbs template inserted
window.__INITIAL_STATE || {},
compose(
enhancer,
applyMiddleware(middleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
);

connect(store);
const initialLocation = store.getState().router;
if (initialLocation) {
store.dispatch(initializeCurrentLocation(initialLocation));
Expand Down
4 changes: 2 additions & 2 deletions demo/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const Root = require('../client/demo').default;

const createStore = redux.createStore;
const combineReducers = redux.combineReducers;
const compose = redux.compose;
const applyMiddleware = redux.applyMiddleware;

const PORT = 4567;
Expand Down Expand Up @@ -83,9 +82,10 @@ app.get('/*', (req, res) => {
const store = createStore(
combineReducers({ router: router.reducer }),
initialState,
compose(router.enhancer, applyMiddleware(router.middleware))
applyMiddleware(router.middleware)
);

router.connect(store);
const content = renderToString(wrap(store)(Root));

return res.send(
Expand Down
26 changes: 5 additions & 21 deletions src/enhancer.js → src/connector.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,26 @@
// @flow

import type { StoreCreator, Reducer, StoreEnhancer } from 'redux';
import type { Store } from 'redux';
import type { History } from 'history';

import type { Location } from './types';

import qs from 'query-string';

import { POP } from './types';
import { locationDidChange, didReplaceRoutes, replace } from './actions';

import matchCache from './util/match-cache';

type InitialState = {
router: Location
};

type EnhancerArgs = {|
type ConnectorArgs = {|
history: History,
matchRoute: Function,
createMatcher: Function
|};
export default ({ history, matchRoute, createMatcher }: EnhancerArgs) => (
createStore: StoreCreator<*, *>
) => (
userReducer: Reducer<*, *>,
initialState: InitialState,
enhancer: StoreEnhancer<*, *>

export default ({ history, matchRoute, createMatcher }: ConnectorArgs) => (
store: Store<*, *>
) => {
let currentMatcher = matchRoute;

const store = createStore(userReducer, initialState, enhancer);

// Replace the matcher when replacing routes
store.subscribe(() => {
const {
Expand Down Expand Up @@ -75,9 +64,4 @@ export default ({ history, matchRoute, createMatcher }: EnhancerArgs) => (
})
);
});

return {
...store,
matchRoute
};
};
4 changes: 2 additions & 2 deletions src/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Location } from './types';

import reducer from './reducer';
import middleware from './middleware';
import enhancer from './enhancer';
import connector from './connector';

import { default as matcherFactory } from './util/create-matcher';
import validateRoutes from './util/validate-routes';
Expand Down Expand Up @@ -36,7 +36,7 @@ export default ({
}
}),
middleware: middleware({ history }),
enhancer: enhancer({
connect: connector({
history,
matchRoute,
createMatcher
Expand Down
17 changes: 6 additions & 11 deletions test/enhancer.spec.js → test/connector.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import chai, { expect } from 'chai';
import sinonChai from 'sinon-chai';

import { combineReducers, compose, createStore, applyMiddleware } from 'redux';
import { combineReducers, createStore, applyMiddleware } from 'redux';

import { PUSH, REPLACE_ROUTES } from '../src/types';
import install from '../src/install';
Expand All @@ -11,7 +11,7 @@ import defaultRoutes from './test-util/fixtures/routes';

chai.use(sinonChai);

describe('Router store enhancer', () => {
describe('Router store connector', () => {
let store;
let historyStub;
let listenStub;
Expand All @@ -24,7 +24,7 @@ describe('Router store enhancer', () => {
const replace = sandbox.spy(() => listen(listenStub));
historyStub = { push, replace, listen };

const { reducer, middleware, enhancer } = install({
const { reducer, middleware, connect } = install({
routes: defaultRoutes,
history: historyStub,
location: { pathname: '/' }
Expand All @@ -33,8 +33,9 @@ describe('Router store enhancer', () => {
store = createStore(
combineReducers({ router: reducer }),
{},
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);
connect(store);
sandbox.spy(store, 'dispatch');
});

Expand All @@ -49,10 +50,6 @@ describe('Router store enhancer', () => {
expect(store.dispatch).to.be.calledOnce;
});

it('attaches the matcher to the store', () => {
expect(store).to.have.property('matchRoute');
});

it('replaces routes', () => {
store.dispatch({
type: REPLACE_ROUTES,
Expand All @@ -64,9 +61,7 @@ describe('Router store enhancer', () => {
}
});

// This dispatch isn't the dispatch used in the enhancer
// (each enhancer has its own copy of dispatch)
expect(store.dispatch).to.be.calledOnce;
expect(store.dispatch).to.be.calledThrice;
expect(historyStub.replace).to.be.calledOnce;
expect(listenStub).to.be.calledOnce;

Expand Down
14 changes: 8 additions & 6 deletions test/environment/browser-router.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import chai, { expect } from 'chai';
import sinonChai from 'sinon-chai';

import { applyMiddleware, combineReducers, createStore, compose } from 'redux';
import { applyMiddleware, combineReducers, createStore } from 'redux';

import routerForBrowser from '../../src/environment/browser-router';

Expand All @@ -10,8 +10,8 @@ import routes from '../test-util/fixtures/routes';
chai.use(sinonChai);

describe('Browser router', () => {
it('creates a browser store enhancer using history location', () => {
const { enhancer, middleware, reducer } = routerForBrowser({
it('creates a browser store connector using history location', () => {
const { connect, middleware, reducer } = routerForBrowser({
routes,
history: {
location: {
Expand All @@ -25,8 +25,9 @@ describe('Browser router', () => {
const store = createStore(
combineReducers({ router: reducer }),
{},
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);
connect(store);
const state = store.getState();
expect(state).to.have.nested.property('router.pathname', '/home');
expect(state).to.have.nested.property('router.search', '?get=schwifty');
Expand All @@ -37,7 +38,7 @@ describe('Browser router', () => {
});

it('supports basenames', () => {
const { enhancer, middleware, reducer } = routerForBrowser({
const { connect, middleware, reducer } = routerForBrowser({
routes,
basename: '/cob-planet',
history: {
Expand All @@ -52,8 +53,9 @@ describe('Browser router', () => {
const store = createStore(
combineReducers({ router: reducer }),
{},
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);
connect(store);
const state = store.getState();
expect(state).to.have.nested.property('router.basename', '/cob-planet');
expect(state).to.have.nested.property('router.pathname', '/home');
Expand Down
14 changes: 8 additions & 6 deletions test/environment/express-router.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import chai, { expect } from 'chai';
import sinonChai from 'sinon-chai';

import { applyMiddleware, combineReducers, createStore, compose } from 'redux';
import { applyMiddleware, combineReducers, createStore } from 'redux';

import routerForExpress from '../../src/environment/express-router';

Expand All @@ -10,8 +10,8 @@ import routes from '../test-util/fixtures/routes';
chai.use(sinonChai);

describe('Express router', () => {
it('creates a server store enhancer using Express request object', () => {
const { enhancer, middleware, reducer } = routerForExpress({
it('creates a server store connector using Express request object', () => {
const { connect, middleware, reducer } = routerForExpress({
routes,
request: {
path: '/home',
Expand All @@ -21,8 +21,9 @@ describe('Express router', () => {
const store = createStore(
combineReducers({ router: reducer }),
{},
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);
connect(store);
const state = store.getState();
expect(state).to.have.nested.property('router.pathname', '/home');
expect(state).to.have.nested.property('router.search', '?get=schwifty');
Expand All @@ -32,7 +33,7 @@ describe('Express router', () => {
});

it('supports basenames', () => {
const { enhancer, middleware, reducer } = routerForExpress({
const { connect, middleware, reducer } = routerForExpress({
routes,
request: {
baseUrl: '/cob-planet',
Expand All @@ -43,8 +44,9 @@ describe('Express router', () => {
const store = createStore(
combineReducers({ router: reducer }),
{},
compose(enhancer, applyMiddleware(middleware))
applyMiddleware(middleware)
);
connect(store);
const state = store.getState();
expect(state).to.have.nested.property('router.basename', '/cob-planet');
expect(state).to.have.nested.property('router.pathname', '/home');
Expand Down
Loading