Skip to content

Instantly share code, notes, and snippets.

@xcarpentier
Forked from 73nko/firebase-hook.js
Created January 17, 2020 10:48
Show Gist options
  • Save xcarpentier/842a485bb30ba3edf533d8f5103ebb63 to your computer and use it in GitHub Desktop.
Save xcarpentier/842a485bb30ba3edf533d8f5103ebb63 to your computer and use it in GitHub Desktop.
React Hooks for loading Firebase Data
import React, { useReducer, useEffect, useRef } from 'react';
import firebase from 'firebase/app';
import equal from 'deep-equal';
function filterKeys(raw, allowed) {
if (!raw) {
return raw;
}
let s = new Set(allowed);
return Object.keys(raw)
.filter(key => s.has(key))
.reduce((obj, key) => {
obj[key] = raw[key];
return obj;
}, {});
}
export const useDbData = (paths) => {
let unsubscribes = useRef({})
let [data, dispatch] = useReducer((d, action) => {
let {type, path, payload} = action
switch (type) {
case 'upsert':
if (payload) {
return Object.assign({}, d, {[path]: payload})
} else {
let newData = Object.assign({}, d)
delete newData[path]
return newData
}
default:
throw new Error('bad type to reducer', type)
}
}, {})
useEffect(() => {
for (let path of Object.keys(paths)) {
if (unsubscribes.current.hasOwnProperty(path)) {
continue
}
let ref = firebase.database().ref(path)
let lastVal = undefined
let f = ref.on('value', snap => {
let val = snap.val()
val = paths[path] ? filterKeys(val, paths[path]) : val
if (!equal(val, lastVal)) {
dispatch({type: 'upsert', payload: val, path})
lastVal = val
}
})
unsubscribes.current[path] = () => ref.off('value', f)
}
let pathSet = new Set(Object.keys(paths))
for (let path of Object.keys(unsubscribes.current)) {
if (!pathSet.has(path)) {
unsubscribes.current[path]()
delete unsubscribes.current[path]
dispatch({type: 'upsert', path})
}
}
})
useEffect(() => {
return () => {
for (let unsubscribe of Object.values(unsubscribes.current)) {
unsubscribe()
}
}
}, [])
return data
}
export const useDbDatum = (path, allowed=null) => {
let datum = useDbData(path ? {[path]: allowed} : {})
if (datum[path]) {
return datum[path]
}
return null
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment