Skip to content

Commit 063777a

Browse files
committed
intermediate commit. old decorator and connector are still present
1 parent f6ef06e commit 063777a

File tree

10 files changed

+555
-180
lines changed

10 files changed

+555
-180
lines changed

src/components/createAll.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import createProvider from './createProvider';
22
import createProvideDecorator from './createProvideDecorator';
33

44
import createConnector from './createConnector';
5+
import createConnectDecoratorOld from './createConnectDecoratorOld';
56
import createConnectDecorator from './createConnectDecorator';
6-
import createConnectWrapper from './createConnectWrapper';
77

88
export default function createAll(React) {
99
// Wrapper components
@@ -12,10 +12,8 @@ export default function createAll(React) {
1212

1313
// Higher-order components (decorators)
1414
const provide = createProvideDecorator(React, Provider);
15-
const connectDecorate = createConnectDecorator(React, Connector);
16-
const connect = createConnectWrapper(React);
15+
const connectDecoratorOld = createConnectDecoratorOld(React, Connector);
16+
const connect = createConnectDecorator(React);
1717

18-
19-
20-
return { Provider, Connector, provide, connectDecorate, connect };
18+
return { Provider, Connector, provide, connect, connectDecoratorOld };
2119
}

src/components/createConnectDecorator.js

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,121 @@
1+
import createStoreShape from '../utils/createStoreShape';
12
import getDisplayName from '../utils/getDisplayName';
23
import shallowEqualScalar from '../utils/shallowEqualScalar';
4+
import shallowEqual from '../utils/shallowEqual';
5+
import isPlainObject from '../utils/isPlainObject';
6+
import wrapActionCreators from '../utils/wrapActionCreators';
7+
import invariant from 'invariant';
38

4-
export default function createConnectDecorator(React, Connector) {
5-
const { Component } = React;
9+
const emptySelector = () => ({});
610

7-
return function connect(select) {
8-
return DecoratedComponent => class ConnectorDecorator extends Component {
9-
static displayName = `Connector(${getDisplayName(DecoratedComponent)})`;
11+
const emptyBinder = () => ({});
12+
13+
const identityMerge = (slice, actionsCreators, props) => ({...slice, ...actionsCreators, ...props});
14+
15+
16+
export default function createConnectDecorator(React) {
17+
const { Component, PropTypes } = React;
18+
const storeShape = createStoreShape(PropTypes);
19+
20+
return function connect(select, dispatchBinder = emptyBinder, mergeHandler = identityMerge) {
21+
22+
const subscribing = select ? true : false;
23+
const selectState = select || emptySelector;
24+
const bindActionCreators = isPlainObject(dispatchBinder) ? wrapActionCreators(dispatchBinder) : dispatchBinder;
25+
const merge = mergeHandler;
26+
27+
return DecoratedComponent => class ConnectDecorator extends Component {
28+
static displayName = `ConnectDecorator(${getDisplayName(DecoratedComponent)})`;
1029
static DecoratedComponent = DecoratedComponent;
1130

12-
shouldComponentUpdate(nextProps) {
13-
return !shallowEqualScalar(this.props, nextProps);
31+
static contextTypes = {
32+
store: storeShape.isRequired
33+
};
34+
35+
shouldComponentUpdate(nextProps, nextState) {
36+
return (this.subscribed && !this.isSliceEqual(this.state.slice, nextState.slice)) ||
37+
!shallowEqualScalar(this.props, nextProps);
1438
}
1539

16-
render() {
17-
return (
18-
<Connector select={state => select(state, this.props)}>
19-
{stuff => <DecoratedComponent {...stuff} {...this.props} />}
20-
</Connector>
40+
isSliceEqual(slice, nextSlice) {
41+
const isRefEqual = slice === nextSlice;
42+
if (isRefEqual) {
43+
return true;
44+
} else if (typeof slice !== 'object' || typeof nextSlice !== 'object') {
45+
return isRefEqual;
46+
}
47+
return shallowEqual(slice, nextSlice);
48+
}
49+
50+
constructor(props, context) {
51+
super(props, context);
52+
this.state = {
53+
...this.selectState(props, context),
54+
...this.bindActionCreators(context)
55+
};
56+
}
57+
58+
componentDidMount() {
59+
if (subscribing) {
60+
this.subscribed = true;
61+
this.unsubscribe = this.context.store.subscribe(::this.handleChange);
62+
}
63+
}
64+
65+
componentWillUnmount() {
66+
if (subscribing) {
67+
this.unsubscribe();
68+
}
69+
}
70+
71+
handleChange(props = this.props) {
72+
const nextState = this.selectState(props, this.context);
73+
if (!this.isSliceEqual(this.state.slice, nextState.slice)) {
74+
this.setState(nextState);
75+
}
76+
}
77+
78+
selectState(props = this.props, context = this.context) {
79+
const state = context.store.getState();
80+
const slice = selectState(state);
81+
82+
invariant(
83+
isPlainObject(slice),
84+
'The return value of `select` prop must be an object. Instead received %s.',
85+
slice
86+
);
87+
88+
return { slice };
89+
}
90+
91+
bindActionCreators(context = this.context) {
92+
const { dispatch } = context.store;
93+
const actionCreators = bindActionCreators(dispatch);
94+
95+
invariant(
96+
isPlainObject(actionCreators),
97+
'The return value of `bindActionCreators` prop must be an object. Instead received %s.',
98+
actionCreators
99+
);
100+
101+
return { actionCreators };
102+
}
103+
104+
merge(props = this.props, state = this.state) {
105+
const { slice, actionCreators } = state;
106+
const merged = merge(slice, actionCreators, props);
107+
108+
invariant(
109+
isPlainObject(merged),
110+
'The return value of `merge` prop must be an object. Instead received %s.',
111+
merged
21112
);
113+
114+
return merged;
115+
}
116+
117+
render() {
118+
return <DecoratedComponent {...this.merge()} />;
22119
}
23120
};
24121
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import getDisplayName from '../utils/getDisplayName';
2+
import shallowEqualScalar from '../utils/shallowEqualScalar';
3+
4+
export default function createConnectDecorator(React, Connector) {
5+
const { Component } = React;
6+
7+
return function connect(select) {
8+
return DecoratedComponent => class ConnectorDecorator extends Component {
9+
static displayName = `Connector(${getDisplayName(DecoratedComponent)})`;
10+
static DecoratedComponent = DecoratedComponent;
11+
12+
shouldComponentUpdate(nextProps) {
13+
return !shallowEqualScalar(this.props, nextProps);
14+
}
15+
16+
render() {
17+
return (
18+
<Connector select={state => select(state, this.props)}>
19+
{stuff => <DecoratedComponent {...stuff} {...this.props} />}
20+
</Connector>
21+
);
22+
}
23+
};
24+
};
25+
}

src/components/createConnectWrapper.js

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

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import React from 'react';
22
import createAll from './components/createAll';
33

4-
export const { Provider, Connector, provide, connectDecorate, connect } = createAll(React);
4+
export const { Provider, Connector, provide, connect, connectDecoratorOld } = createAll(React);

src/native.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import React from 'react-native';
22
import createAll from './components/createAll';
33

4-
export const { Provider, Connector, provide, connectDecorate, connect } = createAll(React);
4+
export const { Provider, Connector, provide, connect, connectDecoratorOld } = createAll(React);

src/utils/wrapActionCreators.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { bindActionCreators } from 'redux'
1+
import { bindActionCreators } from 'redux';
22

3-
export default function wrapActionCreators (actionCreators) {
3+
export default function wrapActionCreators(actionCreators) {
44
return dispatch => bindActionCreators(actionCreators, dispatch);
5-
}
5+
}

0 commit comments

Comments
 (0)