Skip to content

Commit 6954066

Browse files
committed
Extract React-independent Dispatcher
1 parent 022c8ea commit 6954066

File tree

11 files changed

+100
-63
lines changed

11 files changed

+100
-63
lines changed

examples/containers/App.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
import React from 'react';
2-
import { Dispatcher, composeStores } from 'redux';
2+
import { Dispatcher, Provider, composeStores } from 'redux';
33
import CounterApp from './CounterApp';
44
import TodoApp from './TodoApp';
55
import * as stores from '../stores/index';
66

7+
const dispatcher = new Dispatcher(composeStores(stores));
8+
79
export default class App {
810
render() {
911
return (
10-
<Dispatcher store={composeStores(stores)}>
12+
<Provider dispatcher={dispatcher}>
1113
{() =>
1214
<div>
1315
<CounterApp />
1416
<TodoApp />
1517
</div>
1618
}
17-
</Dispatcher>
19+
</Provider>
1820
);
1921
}
2022
}

examples/containers/CounterApp.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React from 'react';
2-
import { inject } from 'redux';
2+
import { connect } from 'redux';
33
import Counter from '../components/Counter';
44
import * as CounterActions from '../actions/CounterActions';
55

6-
@inject({
6+
@connect({
77
actions: CounterActions,
88
select: state => ({
99
counter: state.counter

examples/containers/TodoApp.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import React from 'react';
2-
import { Injector } from 'redux';
2+
import { Connector } from 'redux';
33
import AddTodo from '../components/AddTodo';
44
import TodoList from '../components/TodoList';
55
import * as TodoActions from '../actions/TodoActions';
66

77
export default class TodoApp {
88
render() {
99
return (
10-
<Injector actions={TodoActions}
11-
select={state => state.todos}>
10+
<Connector actions={TodoActions}
11+
select={state => state.todos}>
1212
{this.renderChild}
13-
</Injector>
13+
</Connector>
1414
);
1515
}
1616

src/Dispatcher.js

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,23 @@
1-
import { PropTypes } from 'react';
2-
31
function dispatch(store, atom, action) {
42
return store(atom, action);
53
}
64

75
export default class Dispatcher {
8-
static propTypes = {
9-
store: PropTypes.func.isRequired,
10-
children: PropTypes.func.isRequired
11-
};
12-
13-
static childContextTypes = {
14-
redux: PropTypes.object.isRequired
15-
};
16-
17-
getChildContext() {
18-
return { redux: this };
19-
}
20-
21-
constructor(props) {
6+
constructor(store, atom) {
7+
this.store = store;
8+
this.atom = atom;
229
this.subscriptions = [];
23-
this.emitChange = this.emitChange.bind(this);
24-
this.dispatch = this.dispatch.bind(this);
10+
this.dispatch({});
11+
}
2512

26-
const initialAtom = dispatch(props.store, undefined, {});
27-
this.setAtom(initialAtom);
13+
receive(dispatcher) {
14+
this.atom = dispatcher.atom;
15+
this.subscriptions = dispatcher.subscriptions;
16+
this.dispatch({});
2817
}
2918

3019
dispatch(action) {
31-
const nextAtom = dispatch(this.props.store, this.atom, action);
20+
const nextAtom = dispatch(this.store, this.atom, action);
3221
this.setAtom(nextAtom);
3322
}
3423

@@ -52,8 +41,8 @@ export default class Dispatcher {
5241
subscriptions.forEach(listener => listener(atom));
5342
}
5443

55-
render() {
56-
const { children } = this.props;
57-
return children();
44+
dispose() {
45+
this.atom = undefined;
46+
this.subscriptions = [];
5847
}
5948
}

src/addons/dispatch.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/Injector.js renamed to src/components/Connector.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Component, PropTypes } from 'react';
22
import identity from 'lodash/utility/identity';
33
import mapValues from 'lodash/object/mapValues';
4-
import shallowEqual from './utils/shallowEqual';
4+
import shallowEqual from '../utils/shallowEqual';
55

6-
export default class Injector extends Component {
6+
export default class Connector extends Component {
77
static contextTypes = {
88
redux: PropTypes.object.isRequired
99
};

src/components/Provider.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { PropTypes } from 'react';
2+
import Dispatcher from '../Dispatcher';
3+
4+
export default class Provider {
5+
static propTypes = {
6+
dispatcher: PropTypes.instanceOf(Dispatcher).isRequired,
7+
children: PropTypes.func.isRequired
8+
};
9+
10+
static childContextTypes = {
11+
redux: PropTypes.instanceOf(Provider).isRequired
12+
};
13+
14+
getChildContext() {
15+
return { redux: this };
16+
}
17+
18+
constructor() {
19+
this.dispatch = this.dispatch.bind(this);
20+
}
21+
22+
componentWillReceiveProps(nextProps) {
23+
nextProps.dispatcher.receive(this.props.dispatcher);
24+
this.props.dispatcher.dispose();
25+
}
26+
27+
componentWillUnmount() {
28+
this.props.dispatcher.dispose();
29+
}
30+
31+
subscribe(listener) {
32+
return this.props.dispatcher.subscribe(listener);
33+
}
34+
35+
dispatch(action) {
36+
return this.props.dispatcher.dispatch(action);
37+
}
38+
39+
render() {
40+
const { children } = this.props;
41+
return children();
42+
}
43+
}

src/addons/inject.js renamed to src/components/connect.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import React from 'react';
2-
import Injector from '../Injector';
2+
import Connector from './Connector';
33
import getDisplayName from '../utils/getDisplayName';
44
import shallowEqualScalar from '../utils/shallowEqualScalar';
55

66
function mergeAll({ props, state, actions }) {
77
return { ...props, ...state, ...actions };
88
}
99

10-
export default function inject(
10+
export default function connect(
1111
{ actions: actionsToInject, select },
1212
getChildProps = mergeAll
1313
) {
14-
return DecoratedComponent => class InjectorDecorator {
15-
static displayName = `Injector(${getDisplayName(DecoratedComponent)})`;
14+
return DecoratedComponent => class ConnectorDecorator {
15+
static displayName = `Connector(${getDisplayName(DecoratedComponent)})`;
1616

1717
shouldComponentUpdate(nextProps) {
1818
return !shallowEqualScalar(this.props, nextProps);
@@ -24,10 +24,10 @@ export default function inject(
2424

2525
render() {
2626
return (
27-
<Injector actions={actionsToInject}
27+
<Connector actions={actionsToInject}
2828
select={select}>
2929
{this.renderChild}
30-
</Injector>
30+
</Connector>
3131
);
3232
}
3333

src/components/provide.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import Provider from './Provider';
3+
import getDisplayName from '../utils/getDisplayName';
4+
5+
export default function provide(store) {
6+
return DecoratedComponent => class ProviderDecorator {
7+
static displayName = `Provider(${getDisplayName(DecoratedComponent)})`;
8+
9+
render() {
10+
return (
11+
<Provider store={store}>
12+
{props => <DecoratedComponent {...this.props} {...props} />}
13+
</Provider>
14+
);
15+
}
16+
};
17+
}

src/index.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
// Wrapper components
1+
// Core
22
export Dispatcher from './Dispatcher';
3-
export Injector from './Injector';
3+
4+
// Wrapper components
5+
export Provider from './components/Provider';
6+
export Connector from './components/Connector';
47

58
// Higher-order components (decorators)
6-
export dispatch from './addons/dispatch';
7-
export inject from './addons/inject';
9+
export provide from './components/provide';
10+
export connect from './components/connect';
811

912
// Utilities
10-
export composeStores from './addons/composeStores';
13+
export composeStores from './utils/composeStores';
File renamed without changes.

0 commit comments

Comments
 (0)