-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prototype React 16 context #19
Changes from 3 commits
3896651
c913c96
e01f5e7
3ae64e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,30 @@ | ||
const { Component, Children } = require('react'); | ||
const React = require('react'); | ||
const {Children, Component} = React; | ||
const PropTypes = require('prop-types'); | ||
const ConnectBackboneToReactContext = require('./context.js'); // eslint-disable-line no-unused-vars | ||
|
||
class BackboneProvider extends Component { | ||
getChildContext() { | ||
return { | ||
models: this.props.models, | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
models: props.models, | ||
}; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to implement Or I wonder if we could just use |
||
render() { | ||
return Children.only(this.props.children); | ||
return ( | ||
<ConnectBackboneToReactContext.Provider value={this.state}> | ||
{Children.only(this.props.children)} | ||
</ConnectBackboneToReactContext.Provider> | ||
); | ||
} | ||
} | ||
|
||
BackboneProvider.propTypes = { | ||
models: PropTypes.object, | ||
children: PropTypes.element.isRequired, | ||
}; | ||
BackboneProvider.childContextTypes = { | ||
models: PropTypes.object, | ||
}; | ||
BackboneProvider.displayName = 'BackboneProvider'; | ||
|
||
module.exports = BackboneProvider; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
const hoistStatics = require('hoist-non-react-statics'); | ||
const { Component, createElement } = require('react'); | ||
const React = require('react'); | ||
const {Component} = React; | ||
const PropTypes = require('prop-types'); | ||
const debounceFn = require('lodash.debounce'); | ||
const ConnectBackboneToReactContext = require('./context.js'); // eslint-disable-line no-unused-vars | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto comment in other file |
||
|
||
function getDisplayName(name) { | ||
return `connectBackboneToReact(${name})`; | ||
|
@@ -28,7 +30,7 @@ module.exports = function connectBackboneToReact( | |
const { | ||
debounce = false, | ||
events = {}, | ||
modelTypes = {}, | ||
modelTypes = {} | ||
} = options; | ||
|
||
function getEventNames(modelName) { | ||
|
@@ -66,39 +68,26 @@ module.exports = function connectBackboneToReact( | |
const displayName = getDisplayName(wrappedComponentName); | ||
|
||
class ConnectBackboneToReact extends Component { | ||
constructor(props, context) { | ||
super(props, context); | ||
constructor(props) { | ||
super(props); | ||
|
||
this.setModels(props, context); | ||
|
||
this.state = mapModelsToProps(this.models, this.props); | ||
this.models = {}; | ||
this.state = {}; | ||
|
||
this.createNewProps = this.createNewProps.bind(this); | ||
this.renderChild = this.renderChild.bind(this); | ||
|
||
if (debounce) { | ||
const debounceWait = typeof debounce === 'number' ? debounce : 0; | ||
this.createNewProps = debounceFn(this.createNewProps, debounceWait); | ||
} | ||
|
||
this.createEventListeners(); | ||
} | ||
|
||
setModels(props, context) { | ||
const models = Object.assign({}, context.models, props.models); | ||
setModels(models = {}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like we don't use this method anymore. |
||
validateModelTypes(models); | ||
this.models = models; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see this being updated ever either. I'm curious if we even need it anymore. |
||
} | ||
|
||
createEventListeners() { | ||
Object.keys(this.models).forEach(mapKey => { | ||
const model = this.models[mapKey]; | ||
// Do not attempt to create event listeners on an undefined model. | ||
if (!model) return; | ||
|
||
this.createEventListener(mapKey, model); | ||
}); | ||
} | ||
|
||
createEventListener(modelName, model) { | ||
getEventNames(modelName).forEach(name => { | ||
model.on(name, this.createNewProps, this); | ||
|
@@ -110,27 +99,34 @@ module.exports = function connectBackboneToReact( | |
// The only case where this flag is encountered is when this component | ||
// is unmounted within an event handler but the 'all' event is still triggered. | ||
// It is covered in a test case. | ||
if (this.hasBeenUnmounted) { | ||
return; | ||
} | ||
if (this.hasBeenUnmounted) return; | ||
|
||
this.setState(mapModelsToProps(this.models, this.props)); | ||
} | ||
|
||
componentWillReceiveProps(nextProps, nextContext) { | ||
this.setModels(nextProps, nextContext); | ||
this.createNewProps(); | ||
|
||
renderChild({ models } = {}) { | ||
const newModels = Object.assign({}, models, this.props.models, this.models); | ||
// Bind event listeners for each model that changed. | ||
Object.keys(this.models).forEach(mapKey => { | ||
const model = this.models[mapKey]; | ||
if ((this.props.models && this.props.models[mapKey] === this.models[mapKey]) || | ||
(this.context.models && this.context.models[mapKey] === this.models[mapKey])) { | ||
Object.keys(newModels).forEach(mapKey => { | ||
const model = newModels[mapKey]; | ||
if (this.models && this.models[mapKey] === newModels[mapKey]) { | ||
return; // Did not change. | ||
} | ||
|
||
this.createEventListener(mapKey, model); | ||
this.models[mapKey] = model; | ||
}); | ||
validateModelTypes(this.models); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be validating models before we create event listeners. If we don't have a test for this already we should add one. |
||
|
||
const wrappedProps = Object.assign( | ||
{}, | ||
mapModelsToProps(this.models, this.props), | ||
this.props | ||
); | ||
|
||
// Don't pass through models prop. | ||
wrappedProps.models = undefined; | ||
return React.createElement(WrappedComponent, wrappedProps); | ||
} | ||
|
||
componentWillUnmount() { | ||
|
@@ -152,16 +148,11 @@ module.exports = function connectBackboneToReact( | |
} | ||
|
||
render() { | ||
const wrappedProps = Object.assign( | ||
{}, | ||
this.state, | ||
this.props | ||
return ( | ||
<ConnectBackboneToReactContext.Consumer> | ||
{this.renderChild} | ||
</ConnectBackboneToReactContext.Consumer> | ||
); | ||
|
||
// Don't pass through models prop. | ||
wrappedProps.models = undefined; | ||
|
||
return createElement(WrappedComponent, wrappedProps); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
const React = require('react'); | ||
module.exports = React.createContext('connectBackboneToReact'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The argument to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, remove file extension.
Also is this eslint still needed?