Skip to content

Instantly share code, notes, and snippets.

@hiasinho
Last active August 29, 2015 14:14
Show Gist options
  • Save hiasinho/7d35cd6929160fa7d7de to your computer and use it in GitHub Desktop.
Save hiasinho/7d35cd6929160fa7d7de to your computer and use it in GitHub Desktop.
React mixin for integrating Backbone
Backbone.React = {} unless Backbone.React
Backbone.React.Base = {} unless Backbone.React.Base
###
Backbone React Base Mixin
=========================
Usage example:
--------------
var ContactCard = React.createClass({
mixins: [Backbone.React.Base.mixin],
render: function() {
return (
<div>
<h1>{@model.get('name')}</h1>
</div>
);
}
});
var person = new Backbone.Model({name: 'Zlatan'})
React.render(<ContactCard model={person} />, document.body);
###
Backbone.React.Base.mixin =
componentWillMount: ->
if @props.fetch && @props.fetch != false
@setAndFetch(@props.collection, @props.fetch)
else
@setCollection(@props.collection) if _.has @props, 'collection'
@setModel(@props.model) if _.has @props, 'model'
setAndFetch: (object, options = {})->
if object instanceof Backbone.Model
object = @setModel object
else if object instanceof Backbone.Collection
object = @setCollection object
else
return false
if _.isBoolean options
object.fetch()
else
object.fetch(options)
setCollection: (collection, fetch = false, options = {}) ->
@collection = collection
@props = _.omit @props, 'collection'
@collection.on 'sync', @collectionDidSync
@collection
setModel: (model, fetch = false) ->
@model = model
@props = _.omit @props, 'model'
@model.on 'change', @modelDidChange
@model
collectionDidSync: (e, model) -> @forceUpdate()
modelDidChange: (e, model) -> @forceUpdate()
###
Backbone React Connect
======================
Usage example:
--------------
var User = Backbone.Model.extend();
var Users = Backbone.Collection.extend({
baseUrl: "http://jsonplaceholder.typicode.com/users",
model: User
});
var ContactList = React.createClass({
mixins: [Backbone.React.connect(Users, true)],
render: function() {
return (
<ul>{@collection.map(this.renderUser)}</ul>
);
},
renderUser: function(user) {
<li>{user.get('email')}</li>
}
});
React.render(<ContactList />, document.body);
###
Backbone.React.connect = (klass, fetchOrData = false) ->
setProps =
componentWillMount: ->
instance = new klass()
@props.fetch = fetchOrData
@props.collection = new klass() if (instance instanceof Backbone.Collection)
@props.model = new klass() if (instance instanceof Backbone.Model)
{ mixins: [setProps, Backbone.React.Base.mixin] }
if (!Backbone.React) {
Backbone.React = {};
}
if (!Backbone.React.Base) {
Backbone.React.Base = {};
}
/*
Backbone React Base Mixin
=========================
Usage example:
--------------
var ContactCard = React.createClass({
mixins: [Backbone.React.Base.mixin],
render: function() {
return (
<div>
<h1>{@model.get('name')}</h1>
</div>
);
}
});
var person = new Backbone.Model({name: 'Zlatan'})
React.render(<ContactCard model={person} />, document.body);
*/
Backbone.React.Base.mixin = {
componentWillMount: function() {
if (this.props.fetch && this.props.fetch !== false) {
return this.setAndFetch(this.props.collection, this.props.fetch);
} else {
if (_.has(this.props, 'collection')) {
this.setCollection(this.props.collection);
}
if (_.has(this.props, 'model')) {
return this.setModel(this.props.model);
}
}
},
setAndFetch: function(object, options) {
if (options == null) {
options = {};
}
if (object instanceof Backbone.Model) {
object = this.setModel(object);
} else if (object instanceof Backbone.Collection) {
object = this.setCollection(object);
} else {
return false;
}
if (_.isBoolean(options)) {
return object.fetch();
} else {
return object.fetch(options);
}
},
setCollection: function(collection, fetch, options) {
if (fetch == null) {
fetch = false;
}
if (options == null) {
options = {};
}
this.collection = collection;
this.props = _.omit(this.props, 'collection');
this.collection.on('sync', this.collectionDidSync);
return this.collection;
},
setModel: function(model, fetch) {
if (fetch == null) {
fetch = false;
}
this.model = model;
this.props = _.omit(this.props, 'model');
this.model.on('change', this.modelDidChange);
return this.model;
},
collectionDidSync: function(e, model) {
return this.forceUpdate();
},
modelDidChange: function(e, model) {
return this.forceUpdate();
}
};
/*
Backbone React Connect
======================
Usage example:
--------------
var User = Backbone.Model.extend();
var Users = Backbone.Collection.extend({
baseUrl: "http://jsonplaceholder.typicode.com/users",
model: User
});
var ContactList = React.createClass({
mixins: [Backbone.React.connect(Users, true)],
render: function() {
return (
<ul>{@collection.map(this.renderUser)}</ul>
);
},
renderUser: function(user) {
<li>{user.get('email')}</li>
}
});
React.render(<ContactList />, document.body);
*/
Backbone.React.connect = function(klass, fetchOrData) {
var setProps;
if (fetchOrData == null) {
fetchOrData = false;
}
setProps = {
componentWillMount: function() {
var instance;
instance = new klass();
this.props.fetch = fetchOrData;
if (instance instanceof Backbone.Collection) {
this.props.collection = new klass();
}
if (instance instanceof Backbone.Model) {
return this.props.model = new klass();
}
}
};
return {
mixins: [setProps, Backbone.React.Base.mixin]
};
};
###################################################################
# Models and Collections
###################################################################
Models = {}
Models.Post = Backbone.Model.extend
urlRoot: "http://jsonplaceholder.typicode.com/posts"
Models.PostCollection = Backbone.Collection.extend
url: 'http://jsonplaceholder.typicode.com/posts'
model: Models.Post
###################################################################
# React Components
###################################################################
Components = {}
Components.PostList = React.createClass
mixins: [Backbone.React.connect(Models.PostCollection, true)]
render: ->
if @collection
<div>
<h1>Posts</h1>
<p>Got {@collection.length} posts</p>
<button onClick={@loadData}>Load Data!</button>
{@collection.map(@renderPost)}
</div>
else
<div>
<h1>Posts</h1>
<p>Got no posts</p>
<button onClick={@loadData}>Load Data!</button>
</div>
renderPost: (post) ->
<Components.Post key={post.id} model={post} />
loadData: ->
@collection.fetch()
Components.Post = React.createClass
mixins: [Backbone.React.Base.mixin]
render: ->
<article className="post">
<h2>{@model.get('title')}</h2>
<button onClick={@changeTitle}>Change</button>
<p>{@model.get('body')}</p>
</article>
changeTitle: ->
@model.set('title',"Random #{_.random(500)}")
React.render <Components.PostList />, document.getElementById('posts')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment