Last active
February 8, 2018 16:14
-
-
Save jlongster/f50f88da616a4d7b3032 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Have some complicated non-React widgets that manipulate DOM? | |
// Do they manage a list of DOM elements? Here's how to wrap it | |
// into a React component so you can "constantly rerender" it. | |
// A dumb non-react widget that manually manage some DOM node that | |
// represent a list of items | |
function NonReactWidget(node) { | |
this.node = node; | |
} | |
NonReactWidget.prototype = { | |
addItem: function(item) { | |
// construct a DOM element representing the item | |
var domElement = ...; | |
this.node.appendChild(domElement); | |
} | |
removeItem: function(item) { | |
// remove the item from the list (need to find it somehow) | |
} | |
updateItem: function(item) { | |
// update the item in the list (need to find it and figure out how | |
// to update it, there's probably constraints here already since | |
// you weren't using React). You might even be able to just ignore | |
// this (with my use case I can, nothing is ever updated) | |
} | |
}; | |
// A React interface. We don't want to carefully call | |
// `addItem`/`removeItem` ourselves, we want to throw an array of | |
// items at it like we would with React components. The `Item` | |
// component is a stub that works with React's vdom system but gives | |
// us lifecycle events to actually propagate the change into the DOM. | |
const Item = React.createClass({ | |
componentDidMount: function() { | |
this.props.view.addItem(this.props.item); | |
}, | |
componentWillUnmount: function() { | |
this.props.view.removeItem(this.props.item); | |
}, | |
componentWillReceiveProps: function(nextProps) { | |
this.props.view.updateItem(nextProps.item); | |
} | |
render: function() { | |
return null; | |
} | |
}); | |
const Items = React.createClass({ | |
componentDidMount: function() { | |
this._view = new NonReactWidget(); | |
}, | |
render: function() { | |
return dom.ul( | |
null, | |
// Create a list of `Item` elements, they are stubs that let | |
// React do its diffing magic | |
dom.li(null, map(this.props.items, item => { | |
return Item({ item: item, | |
view: this._view }); | |
})) | |
); | |
} | |
}); | |
React.render(React.createElement(Items, { items: items }), | |
mountPoint); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
First off, thanks for this, just when I needed it...
I did find one bug,
this._view
will throw error duringrender
as it isn't instantiated until mount. I fixed that by tracking isMounted state, and only rendering children once component is mounted. In addition, I also added ability for parent to handle unmount as well incase just unmounting children wasn't good enough (common with jQuery plugins to free up listeners) at https://gist.github.com/nishp1/b3c9ac3d82603df4bf73.