Skip to content

Commit 639c076

Browse files
committed
Track changes by version in Connect
1 parent 9fba95e commit 639c076

File tree

1 file changed

+46
-19
lines changed

1 file changed

+46
-19
lines changed

src/next/connect.js

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { Component, PropTypes, createElement } from 'react'
22
import hoistStatics from 'hoist-non-react-statics'
33
import invariant from 'invariant'
4-
import result from 'lodash/result';
4+
import toPath from 'lodash/toPath';
5+
import isFunction from 'lodash/isFunction';
6+
import isString from 'lodash/isString';
7+
import memoize from 'lodash/memoize';
58

69
import { create } from './create'
710

@@ -12,39 +15,65 @@ const storeShape = PropTypes.shape({
1215
getState: PropTypes.func.isRequired
1316
});
1417

15-
export function connect(namespace) {
18+
19+
const connectNamespace = memoize(create);
20+
21+
22+
export function connect(namespace, reducer) {
23+
invariant(isString(namespace) || isFunction(namespace),
24+
`Expected "namespace" to be of type string or function`
25+
);
26+
1627
return function wrapWithComponent (WrappedComponent) {
1728
class Connect extends Component {
1829
constructor(props, context) {
19-
super(props, context)
30+
super(...arguments);
31+
2032
this.store = props.store || context.store
2133

2234
invariant(this.store,
2335
`Could not find "store" in either the context or ` +
2436
`props of "${this.constructor.displayName}". `
2537
)
2638

27-
this.childProps = create(namespace, this.store)
39+
this.namespace = this.getNamespace(props, this.store)
2840
this.state = {
29-
namespace: result(this.store.getState(), `namespace.${namespace}`, {}),
30-
version: 0
41+
version: this.namespace.version()
3142
}
3243
}
3344

45+
getNamespace(props=this.props, store=this.store) {
46+
return (
47+
connectNamespace(
48+
[ 'namespace',
49+
...toPath(
50+
isFunction(namespace) ?
51+
namespace(state, props) : namespace) ],
52+
store
53+
)
54+
)
55+
}
56+
3457
componentDidMount() {
35-
this.unsubscribe = this.store.subscribe(this.handleChange.bind(this))
58+
if (! this.unsubscribe) {
59+
this.unsubscribe =
60+
this.store.subscribe(this.handleChange.bind(this));
61+
this.handleChange();
62+
}
3663
}
3764

3865
componentWillUnmount() {
39-
this.unsubscribe()
40-
this.unsubscribe = null
66+
if (this.unsubscribe) {
67+
// comma operator, because why not?
68+
this.unsubscribe = this.unsubscribe(), null;
69+
}
4170
}
4271

4372
componentWillUpdate(nextProps, nextState) {
4473
if (nextState.version !== this.state.version) {
45-
this.childProps = {
46-
...this.childProps,
47-
version: nextState.version
74+
this.namespace = {
75+
...this.getNamespace(nextProps),
76+
_version: nextState.version
4877
}
4978
}
5079
}
@@ -54,19 +83,17 @@ export function connect(namespace) {
5483
return
5584
}
5685

57-
const prev = this.state.namespace
58-
const next = result(this.store.getState(), `namespace.${namespace}`, prev)
86+
const prev = this.state.version
87+
const next = this.namespace.version();
88+
5989

6090
if (prev !== next) {
61-
this.setState({
62-
namespace: next,
63-
version: this.state.version + 1
64-
})
91+
this.setState({ version: next })
6592
}
6693
}
6794

6895
render() {
69-
return createElement(WrappedComponent, { ...this.props, [namespace]: this.childProps })
96+
return createElement(WrappedComponent, { ...this.props, [namespace]: this.namespace })
7097
}
7198
}
7299

0 commit comments

Comments
 (0)