Last active
August 29, 2015 14:19
-
-
Save sarink/13fdb1df45e627d783a7 to your computer and use it in GitHub Desktop.
backbone-react
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
// use like: | |
// var sample1 = new SampleModel(); | |
// React.render(<SampleComponent model={sample1} />); | |
define(["underscore", "backbone", "react"], | |
function(_, Backbone, React) { | |
"use strict"; | |
var SampleComponent = React.createClass({ | |
// Give us those sweet react console warnings if we don't pass the right props | |
propTypes: { | |
model: React.PropTypes.instanceOf(Backbone.Model).isRequired | |
}, | |
modelAttrsInState: ["id", "description", "available", "jobNumber"], | |
// This function returns sort of a "viewmodel" for this component | |
computeStateFromModel: function() { | |
var newState = this.props.model.pick(this.modelAttrsInState); | |
// example of bringing in attrs from a nested model or collection, in this case the model has a sampleImagesCollection | |
newState.primaryImageSrc = this.props.model.get("sampleImagesCollection").first().get("src"); | |
return newState; | |
}, | |
// Sets our new state to our "viewmodel" | |
// This could be done without this function, but having it here serves as sort of a hook, just in case you need it | |
setStateFromModel: function() { | |
this.setState(this.computeStateFromModel()); | |
}, | |
getInitialState: function() { | |
return this.computeStateFromModel(); | |
}, | |
// Pure-render-ish, only update if we need to | |
shouldComponentUpdate: function(nextProps, nextState) { | |
return nextProps.model !== this.props.model || !_.isEqual(this.state, nextState); | |
}, | |
// The handler that's called when our model changes, basically just updates our state to our new "viewmodel" | |
_handleModelChange: function() { | |
this.setStateFromModel(); | |
}, | |
// The handler that's called when our sampleImagesCollection changes, basically just updates our state to our new "viewmodel" | |
_handleSampleImagesChange: function() { | |
this.setStateFromModel(); | |
}, | |
// Set up our listeners on our model, and anything else that should update this component (like the nested sampleImagesCollection) | |
componentWillMount: function() { | |
this.listenTo(this.props.model, "change", this._handleModelChange); | |
this.listenTo(this.props.model.get("sampleImagesCollection"), "add remove change", this._handleSampleImagesChange); | |
}, | |
// Destroys our sample model | |
destroyModel: function (event) { | |
this.props.model.destroy(); | |
}, | |
// Handler for when delete is clicked, basically just calls destroyModel | |
_handleDeleteClick: function (event) { | |
this.destroyModel(); | |
}, | |
// A custom function to return an object valueLink can use for two-way binding between BB Models/React Components | |
linkModelState: function(attr, model) { | |
model = model || this.props.model; | |
return { | |
value: this.state[attr], | |
requestChange: function(newValue) { model.set(attr, newValue); } | |
}; | |
}, | |
render: function render() { | |
return ( | |
<div className="sample"> | |
<h3>Sample ID:{this.state.id}</h3> | |
<b>Thumbnail:</b> | |
<img className="sample-thumbnail" src={this.state.primaryImageSrc} /> | |
<br/><br/> | |
<b>Description:</b> | |
<input type="text" className="sample-description" valueLink={this.linkModelState("description")} /> | |
<br/><br/> | |
<b>Available:</b> | |
<input type="checkbox" className="sample-available" checkedLink={this.linkModelState("available")} /> | |
<br/><br/> | |
<b>Job Number:</b> | |
<input type="text" className="sample-job-number" valueLink={this.linkModelState("jobNumber")} /> | |
<br/><br/> | |
<span onClick={this.destroyModel} className="sample-delete">Delete Sample {this.state.id}</span> | |
<br/> | |
<hr/> | |
</div> | |
); | |
}, | |
// The component is unmounting, so have it stop listening for any model/other changes | |
componentWillUnmount: function() { | |
this.stopListening(); | |
} | |
}); | |
// Let's give our React Component some Backboney Events | |
_.extend(SampleComponent.prototype, Backbone.Events); | |
return SampleComponent; | |
}); |
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
define(["underscore", "backbone", "react", "components/SampleComponent"], | |
function(_, Backbone, React, SampleComponent) { | |
"use strict"; | |
var SampleListComponent = React.createClass({ | |
propTypes: { | |
collection: React.PropTypes.instanceOf(Backbone.Collection).isRequired | |
}, | |
// This will trigger an update if the length changes, but if there's some other reason you need to update this listviewcomponent, | |
// (keep in mind the modelviews will update themselves) you might need to call forceUpdate() here | |
computeStateFromCollection: function() { | |
var newState = {}; | |
newState.samplesCount = this.props.collection.length; | |
return newState; | |
}, | |
setStateFromCollection: function() { | |
this.setState(this.computeStateFromCollection()); | |
}, | |
_handleCollectionAddOrRemove: function() { | |
this.setStateFromCollection(); | |
}, | |
componentWillMount: function() { | |
this.listenTo(this.props.collection, "add remove", this._handleCollectionAddOrRemove); | |
}, | |
addModel: function(model) { | |
return <SampleView key={"sample-"+model.cid} model={model} />; | |
}, | |
addNewModel: function() { | |
this.props.collection.add({}); | |
}, | |
render: function() { | |
return ( | |
<div className="sample-list-container"> | |
There are currently {this.state.samplesCount} Samples | |
<button className="add-new-sample" onClick={this.addNewModel}>Add Sample</button> | |
<div className="sample-list"> | |
{this.props.collection.map(this.addModel)} | |
</div> | |
</div> | |
); | |
}, | |
componentWillUnmount: function() { | |
this.stopListening(); | |
} | |
}); | |
_.extend(SampleComponent.prototype, Backbone.Events); | |
return SampleListComponent; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment