Skip to content

Instantly share code, notes, and snippets.

@giacomorebonato
Last active April 6, 2016 17:27
Show Gist options
  • Save giacomorebonato/c044538e4685eea938025a6184c1ac36 to your computer and use it in GitHub Desktop.
Save giacomorebonato/c044538e4685eea938025a6184c1ac36 to your computer and use it in GitHub Desktop.
let inflect = require('i')()
export default function normalize (item, rootRef) {
if (!rootRef) {
throw new Error('rootRef not defined for normalize function')
}
let promises = []
let normalized = Object.assign({}, item)
let keyFields = getKeyFields(item)
let keysFields = getKeysFields(item)
keyFields.forEach((key) => {
let infos = key.split('_')
promises.push(new Promise((resolve, reject) => {
let childRef = infos[0]
rootRef.child(`${childRef}/${item[key]}`).once('value', (snap) => {
if (!snap) {
console.log(
`Not found child ${childRef} with key ${item[key]}`
)
return reject()
}
let data = snap.val()
data.key = snap.key()
data.ref_name = inflect.singularize(childRef)
data.isArrayItem = false
resolve(data)
}, reject)
}))
})
keysFields.forEach((key) => {
let infos = key.split('_')
let childRef = infos[0]
let arrayField = item[key]
arrayField.forEach((childKey) => {
promises.push(new Promise((resolve, reject) => {
rootRef.child(`${childRef}/${childKey}`).once('value', (snap) => {
let data = snap.val()
data.key = snap.key()
data.ref_name = childRef
data.isArrayItem = true
resolve(data)
}, reject)
}))
})
})
return Promise.all(promises).then((values) => {
values.forEach((value) => {
let cleanedRef = Object.assign({}, value, { ref_name: undefined })
if (!value.isArrayItem) {
normalized[value.ref_name] = cleanedRef
} else {
if (!normalized[value.ref_name]) {
normalized[value.ref_name] = []
}
normalized[value.ref_name].push(cleanedRef)
}
})
return normalized
})
}
function getKeyFields (item) {
let keys = Object.keys(item)
let keyFields = []
keys.forEach((key) => {
if (key.endsWith('_key')) {
keyFields.push(key)
}
})
return keyFields
}
function getKeysFields (item) {
let keys = Object.keys(item)
let keyFields = []
keys.forEach((key) => {
if (key.endsWith('_keys')) {
keyFields.push(key)
}
})
return keyFields
}
import React, { Component } from 'react'
import Firebase from 'firebase'
import { FIREBASE_URL } from '../../lib/consts'
import denormalize from './lib/denormalize'
export var FirebaseConnect = (ComposedComponent, collections) => class extends Component {
constructor (props) {
super(props)
this.state = {
rootRef: new Firebase(FIREBASE_URL),
take: 500
}
collections.forEach((collection) => {
this.state[collection] = []
})
}
componentDidMount () {
this.state.rootRef
.child('.info/connected')
.on('value', (data) => {
this.setState({ connected: data.val() === true })
})
this.listenToCollections()
}
stopListeningToCollections () {
collections.forEach((collection) => {
let ref = this.state.rootRef.child(collection)
ref.off('child_added')
ref.off('child_changed')
ref.off('child_removed')
})
}
listenToCollections () {
this.stopListeningToCollections()
collections.forEach((collection) => {
let collectionRef = this.state.rootRef
.child(collection)
.limitToFirst(this.state.take)
.orderByKey()
collectionRef
.on('child_added', (snap, prevKey) => {
let data = snap.val()
data.key = snap.key()
denormalize(data, this.state.rootRef)
.then((normalized) => {
this.setState({
[collection]: this.state[collection].concat([normalized])
})
})
})
collectionRef
.on('child_removed', (data) => {
this.setState({
[collection]: this.state[collection].filter((c) => {
return c.key !== data.key()
})
})
})
collectionRef
.on('child_changed', (snap) => {
let data = snap.val()
data.key = snap.key()
denormalize(data, this.state.rootRef).then((normalized) => {
this.setState({
[collection]: this.state[collection].map((item) => {
if (item.key === normalized.key) {
return normalized
}
return item
})
})
})
})
})
}
componentWillUnmount () {
this.stopListeningToCollections()
}
render () {
return <ComposedComponent {...this.props} {...this.state} />
}
}
export default FirebaseConnect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment