Skip to content

Commit 83efc6f

Browse files
authored
Merge pull request #6 from unfold/firebase-3
Upgrade to Firebase 3 Closes #2 and #5
2 parents 0ea3d84 + 4e45510 commit 83efc6f

32 files changed

+4343
-626
lines changed

.babelrc

Lines changed: 0 additions & 3 deletions
This file was deleted.

.eslintrc

Lines changed: 0 additions & 4 deletions
This file was deleted.

README.md

Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,131 @@
11
React Firebase
22
==============
33

4-
React bindings for [Firebase](https://www.firebase.com).
4+
React bindings for [Firebase](https://firebase.google.com).
55

66
## Installation
77

8-
React Firebase requires **React 0.14 or later.**
9-
108
```
119
npm install --save react-firebase
1210
```
1311

14-
## Usage
15-
16-
### `<Provider firebase>`
12+
React Firebase requires **[React 0.14](https://github.com/facebook/react) and [Firebase 3](https://www.npmjs.com/package/firebase) or later.**
1713

18-
Makes a Firebase refence available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping the root component in `<Provider>`.
19-
20-
If you *really* need to, you can manually pass `firebase` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `firebase` in unit tests, or in non-fully-React codebases. Normally, you should just use `<Provider>`.
21-
22-
#### Props
23-
24-
* `firebase` (*[Firebase](https://www.firebase.com/docs/web/api/firebase/constructor.html)*): A Firebase reference.
25-
* `children` (*ReactElement*) The root of your component hierarchy.
26-
27-
#### Example
28-
29-
##### Vanilla React
14+
## Example
3015

3116
```js
32-
const firebase = new Firebase('https://my-firebase.firebaseio.com');
33-
34-
ReactDOM.render(
35-
<Provider firebase={firebase}>
36-
<MyRootComponent />
37-
</Provider>,
38-
rootEl
17+
import React from 'react'
18+
import firebase from 'firebase'
19+
import { connect } from 'react-firebase'
20+
21+
firebase.initializeApp({
22+
databaseURL: 'https://react-firebase-sandbox.firebaseio.com'
23+
})
24+
25+
const Counter = ({ value, setValue }) => (
26+
<div>
27+
<button onClick={() => setCount(value - 1)}>-</button>
28+
<span>{value}</span>
29+
<button onClick={() => setCount(value + 1)}>+</button>
30+
</div>
3931
)
40-
```
41-
42-
### `connect([mapPropsToSubscriptions], [mapFirebaseToProps], [mergeProps], [options])`
4332

44-
Connects a React component to a Firebase refence.
33+
export default connect((props, ref) => ({
34+
value: 'counterValue',
35+
setValue: value => ref('counterValue').set(value)
36+
}))(TodosApp)
37+
```
4538

46-
It does not modify the component class passed to it.
47-
Instead, it *returns* a new, connected component class, for you to use.
39+
## Usage
4840

49-
#### Arguments
41+
### `connect([mapFirebaseToProps])`
5042

51-
* [`mapPropsToSubscriptions(props): subscriptions`] \(*Function*): If specified, the component will subscribe to Firebase `change` events. Its result must be a plain object, and it will be merged into the component’s props. Each value must either a path to a location in the firebase or a function with the signature `createQuery(firebase): [Query](https://www.firebase.com/docs/web/api/query)`.
43+
Connects a React component to a Firebase App reference.
5244

53-
* [`mapFirebaseToProps(firebase, [ownProps]): actionProps`] \(*Function*): If specified, its result must be a plain object where each value is assumed to be a function that performs modifications to the Firebase. If you omit it, the default implementation just injects `firebase` into your component’s props.
45+
It does not modify the component class passed to it. Instead, it *returns* a new, connected component class, for you to use.
5446

55-
* [`mergeProps(stateProps, actionProps, ownProps): props`] \(*Function*): If specified, it is passed the result of `mapPropsToSubscriptions()`, `mapFirebaseToProps()`, and the parent `props`. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, `Object.assign({}, ownProps, stateProps, actionProps)` is used by default.
47+
#### Arguments
5648

57-
* [`options`] *(Object)* If specified, further customizes the behavior of the connector.
58-
* [`pure = true`] *(Boolean)*: If true, implements `shouldComponentUpdate` and shallowly compares the result of `mergeProps`, preventing unnecessary updates, assuming that the component is a “pure” component and does not rely on any input or state other than its props and subscriptions. *Defaults to `true`.*
49+
* [`mapFirebaseToProps(props, ref, firebaseApp): subscriptions`] \(*Object or Function*): Its result, or the argument itself must be a plain object. Each value must either be a path to a location in your database, a query object or a function. If you omit it, the default implementation just passes `firebaseApp` as a prop to your component.
5950

6051
#### Returns
6152

62-
A React component class that injects subscriptions and actions into your component according to the specified options.
53+
A React component class that passes subscriptions and actions as props to your component according to the specified options.
6354

6455
##### Static Properties
6556

6657
* `WrappedComponent` *(Component)*: The original component class passed to `connect()`.
6758

68-
#### Remarks
69-
70-
* It needs to be invoked two times. The first time with its arguments described above, and a second time, with the component: `connect(mapPropsToSubscriptions, mapFirebaseToProps, mergeProps)(MyComponent)`.
71-
72-
* It does not modify the passed React component. It returns a new, connected component, that you should use instead.
73-
7459
#### Examples
7560

7661
> Runnable examples can be found in the [examples folder](examples/).
7762
78-
##### Inject `firebase` and `todos`
63+
##### Pass `todos` as a prop
7964

80-
> Note: The value of `todos` is analogous to https://my-firebase.firebaseio.com/todos.
65+
> Note: The value of `todos` is the path to your data in Firebase. This is equivalent to `firebase.database().ref('todo')`.
8166
8267
```js
83-
function mapPropsToSubscriptions() {
84-
return { todos: 'todos' }
68+
const mapFirebaseToProps = {
69+
todos: 'todos'
8570
}
8671

87-
export default connect(mapPropsToSubscriptions)(TodoApp)
72+
export default connect(mapFirebaseToProps)(TodoApp)
8873
```
8974

90-
##### Inject `todos` and a function that adds a new todo (`addTodo`)
75+
##### Pass `todos` and a function that adds a new todo (`addTodo`) as props
9176

9277
```js
93-
function mapPropsToSubscriptions() {
94-
return { todos: 'todos' }
95-
}
78+
const mapFirebaseToProps = (props, ref) => ({
79+
todos: 'todos',
80+
addTodo: todo => ref('todos').push(todo)
81+
})
9682

97-
function mapFirebaseToProps(firebase) {
98-
return {
99-
addTodo: function(todo) {
100-
firebase.child('todos').push(todo)
101-
}
102-
}
103-
}
83+
export default connect(mapFirebaseToProps)(TodoApp)
84+
```
85+
86+
##### Pass `todos`, `completedTodos`, a function that completes a todo (`completeTodo`) and one that logs in as props
10487

105-
export default connect(mapPropsToSubscriptions, mapFirebaseToProps)(TodoApp)
88+
```js
89+
const mapFirebaseToProps = (props, ref, { auth }) => ({
90+
todos: 'todos',
91+
completedTodos: {
92+
path: 'todos',
93+
orderByChild: 'completed',
94+
equalTo: true
95+
},
96+
completeTodo = id => ref(`todos/${id}/completed`).set(true),
97+
login: (email, password) => auth().signInWithEmailAndPassword(email, password)
98+
})
99+
100+
export default connect(mapFirebaseToProps)(TodoApp)
106101
```
107102

108-
##### Inject `todos`, `completedTodos` and a function that completes a todo (`completeTodo`)
103+
### `<Provider firebaseApp>`
104+
105+
By default `connect()` will use the [default Firebase App](https://firebase.google.com/docs/reference/js/firebase.app). If you have multiple Firebase App references in your application you may use this to specify the Firebase App reference available to `connect()` calls in the component hierarchy below.
106+
107+
If you *really* need to, you can manually pass `firebaseApp` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `firebaseApp` in unit tests, or in non-fully-React codebases. Normally, you should just use `<Provider>`.
108+
109+
#### Props
110+
111+
* `firebaseApp` (*[App](https://firebase.google.com/docs/reference/js/firebase.app.App)*): A Firebase App reference.
112+
* `children` (*ReactElement*): The root of your component hierarchy.
113+
114+
#### Example
109115

110116
```js
111-
function mapPropsToSubscriptions() {
112-
return {
113-
todos: 'todos',
114-
completedTodos: function(firebase) {
115-
return firebase.child('todos').orderByChild('completed').equalTo(true)
116-
}
117-
}
118-
}
117+
import { initializeApp } from 'firebase'
119118

120-
function mapFirebaseToProps(firebase) {
121-
return {
122-
completeTodo: function(id) {
123-
firebase.child('todos').child(id).child('completed').set(true)
124-
}
125-
}
126-
}
119+
const firebaseApp = initializeApp({
120+
databaseURL: 'https://my-firebase.firebaseio.com'
121+
})
127122

128-
export default connect(mapPropsToSubscriptions, mapFirebaseToProps)(TodoApp)
123+
ReactDOM.render(
124+
<Provider firebaseApp={firebaseApp}>
125+
<MyRootComponent />
126+
</Provider>,
127+
rootEl
128+
)
129129
```
130130

131131
## License

circle.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
machine:
22
node:
3-
version: 5.9.1
3+
version: stable
44

55
dependencies:
6+
pre:
7+
- curl -o- -L https://yarnpkg.com/install.sh | TERM=xterm bash
68
override:
7-
- npm install --ignore-scripts
9+
- yarn
810

911
test:
1012
override:

examples/.eslintrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}]
4+
}
5+
}

examples/basic/Count.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import React, { PropTypes } from 'react';
2-
import { connect } from 'react-firebase';
3-
import { partial } from 'lodash';
1+
import React, { PropTypes } from 'react'
2+
import { partial } from 'lodash'
3+
import { connect } from '../../src'
4+
import { getSandboxedPath } from '../common'
5+
6+
const countPath = getSandboxedPath('count')
47

58
const Count = ({ count, setCount }) => (
69
<div>
@@ -9,16 +12,16 @@ const Count = ({ count, setCount }) => (
912
<button onClick={partial(setCount, count - 1)}>Decrement</button>
1013
<button onClick={partial(setCount, count + 1)}>Increment</button>
1114
</div>
12-
);
15+
)
1316

1417
Count.propTypes = {
1518
count: PropTypes.number,
1619
setCount: PropTypes.func.isRequired,
17-
};
20+
}
1821

19-
const mapPropsToSubscriptions = () => ({ count: 'count' });
20-
const mapFirebaseToProps = firebase => ({
21-
setCount: count => firebase.child('count').set(count),
22-
});
22+
const mapFirebaseToProps = (props, ref) => ({
23+
count: countPath,
24+
setCount: count => ref(countPath).set(count),
25+
})
2326

24-
export default connect(mapPropsToSubscriptions, mapFirebaseToProps)(Count);
27+
export default connect(mapFirebaseToProps)(Count)

examples/basic/index.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
import React from 'react';
2-
import { render } from 'react-dom';
3-
import Count from './Count';
4-
import createDemoRef from '../createDemoRef';
1+
import React from 'react'
2+
import { render } from 'react-dom'
3+
import { initializeDemoApp } from '../common'
4+
import Count from './Count'
55

6-
const firebase = createDemoRef('basic');
6+
initializeDemoApp()
77

8-
const App = () => (
9-
<div>
10-
<Count firebase={firebase} />
11-
</div>
12-
);
13-
14-
render(<App />, document.getElementById('example'));
8+
render(<Count />, document.getElementById('example'))

examples/common.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { initializeApp } from 'firebase/app'
2+
import 'firebase/database'
3+
4+
export const getSandboxedPath = path => `${process.env.SANDBOX_PATH}/${path}`
5+
export const initializeDemoApp = () => initializeApp({
6+
databaseURL: 'https://react-firebase-sandbox.firebaseio.com',
7+
})

examples/complex/AddUser.js

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,50 @@
1-
import React, { Component, PropTypes } from 'react';
2-
import { connect } from 'react-firebase';
1+
import React, { Component, PropTypes } from 'react'
2+
import { connect } from '../../src'
3+
import { getSandboxedPath } from '../common'
4+
5+
const usersPath = getSandboxedPath('complex/users')
36

47
class AddUser extends Component {
58
constructor(props) {
6-
super(props);
9+
super(props)
710

811
this.state = {
912
name: '',
10-
};
13+
}
1114
}
1215

1316
onChange(event) {
14-
const { name, value } = event.target;
17+
const { name, value } = event.target
1518

1619
this.setState({
1720
[name]: value,
18-
});
21+
})
1922
}
2023

2124
onSubmit(event) {
22-
event.preventDefault();
25+
event.preventDefault()
2326

24-
this.props.addUser(this.state.name);
27+
this.props.addUser(this.state.name)
2528
}
2629

2730
render() {
28-
const { name } = this.state;
31+
const { name } = this.state
2932

3033
return (
31-
<form onSubmit={::this.onSubmit}>
32-
<input name="name" value={name} onChange={::this.onChange} />
34+
<form onSubmit={event => this.onSubmit(event)}>
35+
<input name="name" value={name} onChange={event => this.onChange(event)} />
3336
<button type="submit" disabled={!name}>Add user</button>
3437
</form>
35-
);
38+
)
3639
}
3740
}
3841

3942
AddUser.propTypes = {
4043
addUser: PropTypes.func.isRequired,
41-
};
44+
}
4245

43-
const mapFirebaseToProps = firebase => ({
44-
addUser: name => firebase.child('users').push({ name }),
45-
});
46+
const mapFirebaseToProps = (props, ref) => ({
47+
addUser: name => ref(usersPath).push({ name }),
48+
})
4649

47-
export default connect(null, mapFirebaseToProps)(AddUser);
50+
export default connect(mapFirebaseToProps)(AddUser)

0 commit comments

Comments
 (0)