Skip to content

Instantly share code, notes, and snippets.

@gragland
Last active April 22, 2020 00:14
Show Gist options
  • Save gragland/6e4cd47df96efbb7f463287acc96cd94 to your computer and use it in GitHub Desktop.
Save gragland/6e4cd47df96efbb7f463287acc96cd94 to your computer and use it in GitHub Desktop.
// Usage
export function useUser(uid) {
return useQuery(uid && firestore.collection("users").doc(uid));
}
// Custom useQuery hook for Firestore
function useQuery(query) {
const [queryState, setQueryState] = useState({
status: "loading",
data: undefined,
error: null,
});
// Gives us previous query object if query is the same
// ensuring we don't unsubscribe and resubscribe below.
const queryCached = useQueryCache(query);
useEffect(() => {
// Skip if falsy value, as that allows us to wait on needed
// needed data before constructing query and passing it into useQuery.
if (queryCached) {
return queryCached.onSnapshot(
(snapshot) => {
// Get data for collection or individual doc
const data = snapshot.docs
? snapshot.docs.map((doc) => {
// Return array of docs and merge in doc id
return { id: doc.id, ...doc.data() };
})
: snapshot.exists === true
? { id: snapshot.id, ...snapshot.data() }
: null;
setQueryState({
status: "success",
data: data,
error: null,
});
},
(error) => {
setQueryState((state) => ({
status: "error",
data: state.data,
error: error,
}));
}
);
}
}, [queryCached]);
return queryState;
}
function useQueryCache(query) {
// Ref for storing previous query object
const previousRef = useRef();
const previous = previousRef.current;
// Determine if query object is equal to previous
const isEqual =
(!previous && !query) || (previous && query && previous.isEqual(query));
// If not equal update previous to query (for next render)
// and then return new query below.
useEffect(() => {
if (!isEqual) {
previousRef.current = query;
}
});
return isEqual ? previous : query;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment