-
-
Save marcello3d/0e9a1e532954f67c1fbb67c7d18319a6 to your computer and use it in GitHub Desktop.
Experimental ES6 Firebase, Observables, and 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
import React from 'react' | |
export default function connect (propFunctions) { | |
return function wrapWithConnect (WrappedComponent) { | |
return class Connect extends React.Component { | |
static displayName = `Observing${WrappedComponent.displayName}` | |
componentWillMount () { | |
this._subscriptions = Object.keys(propFunctions).map((key) => | |
this._subscribe(key, propFunctions[key](this.props))) | |
} | |
_subscribe (key, result) { | |
const onValue = (value) => { | |
if (this._subscriptions) { | |
this.setState({ [key]: value }) | |
} | |
} | |
const onError = (error) => { | |
if (this._subscriptions) { | |
this.setState({ [`${key}__error`]: error }) | |
} | |
} | |
// check for Observable | |
if (typeof result === 'object' && typeof result.subscribe === 'function') { | |
return result.subscribe(onValue, onError) | |
} | |
if (result instanceof Promise) { | |
result.then(onValue).catch(onError) | |
} else { | |
onValue(result) | |
} | |
return { unsubscribe () {} } | |
} | |
componentWillUnmount () { | |
this._subscriptions.forEach((subscription) => subscription.unsubscribe()) | |
this._subscriptions = null | |
} | |
render () { | |
return ( | |
<WrappedComponent | |
{...this.state} | |
{...this.props} | |
/> | |
) | |
} | |
} | |
} | |
} |
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
import React from 'react' | |
import { observeValue, observeCurrentUser } from './firebase-observable' | |
import connectObserver from './connect-observer' | |
export default connectObserver({ | |
post: ({ postId }) => observeValue(firebase.database().ref('/posts').child(postId)), | |
user: () => observeCurrentUser(firebase.auth()) | |
})(class Post extends React.Component | |
static propTypes = { | |
postId: React.PropTypes.string.isRequired, | |
post: React.PropTypes.shape({ … }), | |
user: React.PropTypes.object | |
}; | |
render () { | |
const { post, user } = this.props | |
return … | |
} | |
})) |
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
import Observable from 'zen-observable' | |
function observeSnapshot (reference, mapper) { | |
return new Observable((observer) => { | |
const onValue = (snapshot) => observer.next(mapper(snapshot)) | |
const onError = (error) => observer.error(error) | |
reference.on('value', onValue, onError) | |
return () => reference.off('value', onValue) | |
}) | |
} | |
export function observeValue (reference) { | |
return observeSnapshot(reference, (snapshot) => snapshot.val()) | |
} | |
export function observeKeys (reference) { | |
return observeSnapshot(reference, (snapshot) => { | |
const keys = [] | |
snapshot.forEach((childSnapshot) => { | |
keys.push(childSnapshot.key) | |
}) | |
return keys | |
}) | |
} | |
export function observeKeyCount (reference) { | |
return observeSnapshot(reference, (snapshot) => snapshot.numChildren()) | |
} | |
export function observeArrayValue (reference) { | |
return observeSnapshot(reference, (snapshot) => { | |
const array = [] | |
snapshot.forEach((childSnapshot) => { | |
const object = { | |
'.key': childSnapshot.key, | |
'.priority': childSnapshot.getPriority() | |
} | |
const value = childSnapshot.val() | |
if (typeof value === 'object') { | |
Object.assign(object, value) | |
} else { | |
object['.value'] = value | |
} | |
array.push(object) | |
}) | |
return array | |
}) | |
} | |
export function observeCurrentUser (firebaseAuth) { | |
return new Observable((observer) => { | |
const onValue = (user) => observer.next(user) | |
const unsubscribe = firebaseAuth.onAuthStateChanged(onValue) | |
onValue(firebaseAuth.currentUser) | |
return unsubscribe | |
}) | |
} |
@marcello3d What would be a good way to handle "actions" (like a set or transaction) along side this? Something comparable to react-redux's mapDispatchToProps
would be nice..
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO:
componentWillReceiveProps
support