Skip to content

Commit 74dafcf

Browse files
authored
Avoid strict mode deprecation errors (#25)
* Switch to new Context API * Avoiding use of deprecated lifecycle methods * Remove old getChildContext from provider * Convert BackboneProvider to function component * Dereference off of require call directly * Fix silly mistake with class -> function refactor * Avoid warnings around forceUpdate before mounting
1 parent 26e566b commit 74dafcf

File tree

5 files changed

+76
-97
lines changed

5 files changed

+76
-97
lines changed

lib/backbone-provider.js

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
1-
const { Component, Children } = require('react');
1+
const { Children, createElement } = require('react');
22
const PropTypes = require('prop-types');
3+
const { Provider } = require('./context');
34

4-
class BackboneProvider extends Component {
5-
getChildContext() {
6-
return {
7-
models: this.props.models,
8-
};
9-
}
10-
11-
render() {
12-
return Children.only(this.props.children);
13-
}
5+
function BackboneProvider(props) {
6+
return createElement(Provider, { value: props.models }, Children.only(props.children));
147
}
158

169
BackboneProvider.propTypes = {
1710
models: PropTypes.object,
1811
children: PropTypes.element.isRequired,
1912
};
20-
BackboneProvider.childContextTypes = {
21-
models: PropTypes.object,
22-
};
2313
BackboneProvider.displayName = 'BackboneProvider';
2414

2515
module.exports = BackboneProvider;

lib/connect-backbone-to-react.js

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const hoistStatics = require('hoist-non-react-statics');
22
const { Component, createElement } = require('react');
33
const PropTypes = require('prop-types');
44
const debounceFn = require('lodash.debounce');
5+
const BackboneToReactContext = require('./context');
56

67
function getDisplayName(name) {
78
return `connectBackboneToReact(${name})`;
@@ -70,9 +71,7 @@ module.exports = function connectBackboneToReact(
7071
constructor(props, context) {
7172
super(props, context);
7273

73-
this.setModels(props, context);
74-
75-
this.state = mapModelsToProps(this.models, this.props);
74+
this.componentIsMounted = false;
7675

7776
this.createNewProps = this.createNewProps.bind(this);
7877
this.setWrappedInstance = this.setWrappedInstance.bind(this);
@@ -85,20 +84,24 @@ module.exports = function connectBackboneToReact(
8584
this.createEventListeners();
8685
}
8786

88-
setModels(props, context) {
89-
const models = Object.assign({}, context.models, props.models);
87+
getModels() {
88+
const models = Object.assign({}, this.context, this.props.models);
9089
validateModelTypes(models);
91-
this.models = models;
90+
return models;
9291
}
9392

9493
createEventListeners() {
95-
Object.keys(this.models).forEach(mapKey => {
96-
const model = this.models[mapKey];
94+
const models = this.getModels();
95+
Object.keys(models).forEach(mapKey => {
96+
const model = models[mapKey];
9797
// Do not attempt to create event listeners on an undefined model.
9898
if (!model) return;
9999

100100
this.createEventListener(mapKey, model);
101101
});
102+
103+
// Store a reference to the models with event listeners for the next update.
104+
this.prevModels = models;
102105
}
103106

104107
createEventListener(modelName, model) {
@@ -118,11 +121,11 @@ module.exports = function connectBackboneToReact(
118121
// The only case where this flag is encountered is when this component
119122
// is unmounted within an event handler but the 'all' event is still triggered.
120123
// It is covered in a test case.
121-
if (this.hasBeenUnmounted) {
124+
// Also bails if we haven't yet mounted, to avoid warnings in strict mode.
125+
if (!this.componentIsMounted) {
122126
return;
123127
}
124-
125-
this.setState(mapModelsToProps(this.models, this.props));
128+
this.forceUpdate();
126129
}
127130

128131
setWrappedInstance(ref) {
@@ -137,58 +140,57 @@ module.exports = function connectBackboneToReact(
137140
return this.wrappedInstance;
138141
}
139142

140-
UNSAFE_componentWillReceiveProps(nextProps, nextContext) { // eslint-disable-line camelcase
141-
this.setModels(nextProps, nextContext);
142-
this.createNewProps();
143+
componentDidMount() {
144+
this.componentIsMounted = true;
145+
}
143146

144-
// Bind event listeners for each model that changed.
145-
Object.keys(this.models).forEach(mapKey => {
146-
const model = this.models[mapKey];
147+
componentDidUpdate() {
148+
// add and remove listeners
149+
const models = this.getModels();
150+
const prevModels = this.prevModels;
147151

148-
// Retrieve old versions of the model from props and context for comparison.
149-
const propsModel = this.props.models ? this.props.models[mapKey] : undefined;
150-
const contextModel = this.context.models ? this.context.models[mapKey] : undefined;
152+
// Bind event listeners for each model that changed.
153+
Object.keys(Object.assign({}, models, prevModels)).forEach(mapKey => {
154+
const model = models[mapKey];
155+
const prevModel = prevModels[mapKey];
151156

152157
// Do not attempt to create event listeners on an undefined model.
153158
if (!model) {
154159
// Instead, if it was previously defined, remove the old listeners.
155-
if (propsModel) {
156-
this.removeEventListener(mapKey, propsModel);
157-
// If a model with the matching mapKey exists in both props and context,
158-
// we only remove listeners from the one in props. We do this because
159-
// only the one in props is actually used in this.models, per the
160-
// Object.assign in setModel.
161-
} else if (contextModel) {
162-
this.removeEventListener(mapKey, contextModel);
160+
if (prevModel) {
161+
this.removeEventListener(mapKey, prevModel);
163162
}
164163
return;
165164
}
166165

167-
if ((propsModel === model) || (contextModel === model)) return; // Did not change.
166+
if (prevModel === model) return; // Did not change.
168167

169168
this.createEventListener(mapKey, model);
170169
});
170+
171+
// Store a reference to the models with event listeners for the next update.
172+
this.prevModels = models;
171173
}
172174

173175
componentWillUnmount() {
174176
if (debounce) {
175177
this.createNewProps.cancel();
176178
}
177179

178-
Object.keys(this.models).forEach(mapKey => {
179-
const model = this.models[mapKey];
180+
Object.keys(this.prevModels).forEach(mapKey => {
181+
const model = this.prevModels[mapKey];
180182
// Do not attempt to remove event listeners on an undefined model.
181183
if (!model) return;
182184
this.removeEventListener(mapKey, model);
183185
});
184186

185-
this.hasBeenUnmounted = true;
187+
this.componentIsMounted = false;
186188
}
187189

188190
render() {
189191
const wrappedProps = Object.assign(
190192
{},
191-
this.state,
193+
mapModelsToProps(this.getModels(), this.props),
192194
this.props
193195
);
194196

@@ -210,7 +212,7 @@ module.exports = function connectBackboneToReact(
210212
ConnectBackboneToReact.WrappedComponent = WrappedComponent;
211213
ConnectBackboneToReact.displayName = displayName;
212214
ConnectBackboneToReact.propTypes = propTypes;
213-
ConnectBackboneToReact.contextTypes = propTypes;
215+
ConnectBackboneToReact.contextType = BackboneToReactContext;
214216

215217
return hoistStatics(ConnectBackboneToReact, WrappedComponent);
216218
};

lib/context.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const { createContext } = require('react');
2+
3+
module.exports = createContext();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"prop-types": "^15.7.2"
3131
},
3232
"peerDependencies": {
33-
"react": "^16.3.0-0"
33+
"react": "^16.6.0-0"
3434
},
3535
"devDependencies": {
3636
"babel-cli": "^6.22.2",

0 commit comments

Comments
 (0)