Skip to content

Commit 52a26aa

Browse files
author
jacobawenger
committed
Added reactFireMixin and Todo app example
Added reactFireMixin Added Todo app example Updated README
1 parent 219f397 commit 52a26aa

File tree

6 files changed

+319
-1
lines changed

6 files changed

+319
-1
lines changed

README.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,43 @@
11
reactFire
22
=========
33

4-
Firebase mixin for React
4+
reactFire is an officially supported [React](http://facebook.github.io/react/) mixin
5+
for [Firebase](http://www.firebase.com/). Firebase provides your React app with a
6+
persistent, real-time backend so you don't need servers to build your React app!
7+
8+
Read our [blog post](http://www.firebase.com/blog/TODO) on using React with Firebase to get started!
9+
10+
API Reference
11+
-------------
12+
To add the reactFire mixin to your component, update the component's mixins property:
13+
14+
var ExampleComponent = React.createClass({
15+
mixins: [reactFireMixin],
16+
...
17+
});
18+
19+
###bindToArray(firebaseRef, bindVar)
20+
21+
Creates a binding between Firebase and the inputted bind variable as an array. The Firebase
22+
reference will be stored in this.firebaseRefs[bindVar].
23+
24+
this.bindToArray(new Firebase("https://<YOUR_FIREBASE>.firebaseio-demo.com/items/"), "items");
25+
26+
###bindToObject(firebaseRef, bindVar)
27+
28+
Creates a binding between Firebase and the inputted bind variable as an object. The Firebase
29+
reference will be stored in this.firebaseRefs[bindVar].
30+
31+
this.bindToObject(new Firebase("https://<YOUR_FIREBASE>.firebaseio-demo.com/items/"), "items");
32+
33+
###unbind(bindVar)
34+
35+
Removes the binding between Firebase and the inputted bind variable. This removes the stored
36+
Firebase reference in this.firebaseRefs[bindVar] and cleans up any event handlers associated
37+
with that Firebase reference.
38+
39+
this.unbind("items");
40+
41+
License
42+
-------
43+
[MIT](http://firebase.mit-license.org).
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/** @jsx React.DOM */
2+
var TodoList2 = React.createClass({
3+
render: function() {
4+
var createItem = function(item) {
5+
return <li>{item.text}</li>;
6+
};
7+
return <ul>{this.props.items.map(createItem)}</ul>;
8+
}
9+
});
10+
11+
var TodoApp2 = React.createClass({
12+
getInitialState: function() {
13+
this.items = [];
14+
return {items: [], text: ""};
15+
},
16+
17+
componentWillMount: function() {
18+
this.firebaseRef = new Firebase("https://reactFireTodoList.firebaseio-demo.com/items/");
19+
this.firebaseRef.on("child_added", function(dataSnapshot) {
20+
this.items.push(dataSnapshot.val());
21+
this.setState({
22+
items: this.items
23+
});
24+
}.bind(this));
25+
},
26+
27+
componentWillUnmount: function() {
28+
this.firebaseRef.off();
29+
},
30+
31+
onChange: function(e) {
32+
this.setState({text: e.target.value});
33+
},
34+
35+
handleSubmit: function(e) {
36+
e.preventDefault();
37+
this.firebaseRef.push({
38+
text: this.state.text
39+
});
40+
this.setState({text: ""});
41+
},
42+
43+
render: function() {
44+
return (
45+
<div>
46+
<TodoList2 items={this.state.items} />
47+
<form onSubmit={this.handleSubmit}>
48+
<input onChange={this.onChange} value={this.state.text} />
49+
<button>{"Add #" + (this.state.items.length + 1)}</button>
50+
</form>
51+
</div>
52+
);
53+
}
54+
});
55+
56+
React.renderComponent(<TodoApp2 />, document.getElementById("todoList2"));
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/** @jsx React.DOM */
2+
var TodoList3 = React.createClass({
3+
render: function() {
4+
var createItem = function(item) {
5+
return <li>{item.text}</li>;
6+
};
7+
return <ul>{this.props.items.map(createItem)}</ul>;
8+
}
9+
});
10+
11+
var TodoApp3 = React.createClass({
12+
mixins: [reactFireMixin],
13+
14+
getInitialState: function() {
15+
return {items: [], text: ""};
16+
},
17+
18+
componentWillMount: function() {
19+
this.bindToArray(new Firebase("https://reactFireTodoList.firebaseio-demo.com/items/"), "items");
20+
},
21+
22+
onChange: function(e) {
23+
this.setState({text: e.target.value});
24+
},
25+
26+
handleSubmit: function(e) {
27+
e.preventDefault();
28+
this.firebaseRefs["items"].push({
29+
text: this.state.text
30+
});
31+
this.setState({text: ""});
32+
},
33+
34+
render: function() {
35+
return (
36+
<div>
37+
<TodoList3 items={this.state.items} />
38+
<form onSubmit={this.handleSubmit}>
39+
<input onChange={this.onChange} value={this.state.text} />
40+
<button>{"Add #" + (this.state.items.length + 1)}</button>
41+
</form>
42+
</div>
43+
);
44+
}
45+
});
46+
47+
React.renderComponent(<TodoApp3 />, document.getElementById("todoList3"));
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/** @jsx React.DOM */
2+
var TodoList1 = React.createClass({
3+
render: function() {
4+
var createItem = function(item) {
5+
return <li>{item.text}</li>;
6+
};
7+
return <ul>{this.props.items.map(createItem)}</ul>;
8+
}
9+
});
10+
11+
var TodoApp1 = React.createClass({
12+
getInitialState: function() {
13+
return {items: [], text: ""};
14+
},
15+
16+
onChange: function(e) {
17+
this.setState({text: e.target.value});
18+
},
19+
20+
handleSubmit: function(e) {
21+
e.preventDefault();
22+
var nextItems = this.state.items.concat([{
23+
text: this.state.text
24+
}]);
25+
this.setState({
26+
items: nextItems,
27+
text: ""
28+
});
29+
},
30+
31+
render: function() {
32+
return (
33+
<div>
34+
<TodoList1 items={this.state.items} />
35+
<form onSubmit={this.handleSubmit}>
36+
<input onChange={this.onChange} value={this.state.text} />
37+
<button>{"Add #" + (this.state.items.length + 1)}</button>
38+
</form>
39+
</div>
40+
);
41+
}
42+
});
43+
44+
React.renderComponent(<TodoApp1 />, document.getElementById("todoList1"));

examples/todoApp/todoApp.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>reactFire Example</title>
5+
6+
<!-- React JS -->
7+
<script src="http://fb.me/react-0.10.0.min.js"></script>
8+
<script src="http://fb.me/JSXTransformer-0.10.0.js"></script>
9+
10+
<!-- Firebase JS -->
11+
<script src="https://cdn.firebase.com/js/client/1.0.11/firebase.js"></script>
12+
13+
<!-- reactFire Mixin -->
14+
<script type="text/jsx" src="../../reactFireMixin.js"></script>
15+
16+
<!-- Custom JS -->
17+
<script type="text/jsx" src="js/todoListOriginal.js"></script>
18+
<script type="text/jsx" src="js/todoListFirebaseExplicit.js"></script>
19+
<script type="text/jsx" src="js/todoListFirebaseImplicit.js"></script>
20+
</head>
21+
<body>
22+
<h1>Plain React</h1>
23+
<div id="todoList1"></div>
24+
25+
<h1>React with explicit Firebase calls</h1>
26+
<div id="todoList2"></div>
27+
28+
<h1>React with reactFire mixin</h1>
29+
<div id="todoList3"></div>
30+
</body>
31+
</html>

reactFireMixin.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
var reactFireMixin = {
2+
/********************/
3+
/* MIXIN LIFETIME */
4+
/********************/
5+
/* Initializes the Firebase binding refs array */
6+
componentWillMount: function() {
7+
this.firebaseRefs = {};
8+
},
9+
10+
/* Removes any remaining Firebase bindings */
11+
componentWillUnmount: function() {
12+
for (var key in this.firebaseRefs) {
13+
this.unbind(key);
14+
};
15+
},
16+
17+
18+
/*************/
19+
/* BINDING */
20+
/*************/
21+
/* Creates a binding between Firebase and the inputted bind variable as an array */
22+
bindToArray: function(firebaseRef, bindVar) {
23+
this._bind(firebaseRef, bindVar, true);
24+
},
25+
26+
/* Creates a binding between Firebase and the inputted bind variable as an object */
27+
bindToObject: function(firebaseRef, bindVar) {
28+
this._bind(firebaseRef, bindVar, false);
29+
},
30+
31+
/* Creates a binding between Firebase and the inputted bind variable as either an array or object */
32+
_bind: function(firebaseRef, bindVar, bindAsArray) {
33+
this.firebaseRefs[bindVar] = firebaseRef;
34+
firebaseRef.on("value", function(dataSnapshot) {
35+
var newState = {};
36+
if (bindAsArray) {
37+
newState[bindVar] = this._toArray(dataSnapshot.val());
38+
}
39+
else {
40+
newState[bindVar] = dataSnapshot.val();
41+
}
42+
this.setState(newState);
43+
}.bind(this));
44+
},
45+
46+
/* Removes the binding between Firebase and the inputted bind variable */
47+
unbind: function(bindVar) {
48+
this.firebaseRefs[bindVar].off("value");
49+
delete this.firebaseRefs[bindVar];
50+
},
51+
52+
53+
/*************/
54+
/* HELPERS */
55+
/*************/
56+
/* Returns true if the inputted object is a number */
57+
_isNumeric: function(obj) {
58+
try {
59+
return (((obj - 0) == obj) && (obj.length > 0));
60+
} catch (e) {
61+
return false;
62+
} // try
63+
}, // isNumeric()
64+
65+
/* Returns true if the inputted object is a JavaScript array */
66+
_isArray: function(obj) {
67+
if (!obj) { return false; }
68+
try {
69+
if (!(obj.propertyIsEnumerable("length"))
70+
&& (typeof obj === "object")
71+
&& (typeof obj.length === "number")) {
72+
for (var idx in obj) {
73+
if (!this._isNumeric(idx)) { return false; }
74+
} // for (var idx in object)
75+
return true;
76+
} else {
77+
return false;
78+
} // if (!(obj.propertyIsEnumerable("length"))...
79+
} catch (e) {
80+
return false;
81+
} // try
82+
}, // isArray()
83+
84+
/* Converts a Firebase list to a JavaScript array */
85+
_toArray: function(list) {
86+
var k, out = [];
87+
if (list) {
88+
if (this._isArray(list)) {
89+
out = list;
90+
}
91+
else if (typeof(list) === "object") {
92+
for (k in list) {
93+
if (list.hasOwnProperty(k)) {
94+
out.push(list[k]);
95+
}
96+
}
97+
}
98+
}
99+
return out;
100+
}
101+
};

0 commit comments

Comments
 (0)