-
Notifications
You must be signed in to change notification settings - Fork 0
/
db.js
134 lines (111 loc) · 3.26 KB
/
db.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { useState, useEffect, useRef } from "react";
import firebase from "./firebase";
const firestore = firebase.firestore();
/**** USERS ****/
// Fetch user data (hook)
// This is called automatically by auth.js and merged into auth.user
export function useUser(uid) {
return useQuery(uid && firestore.collection("users").doc(uid));
}
// Update an existing user
export function updateUser(uid, data) {
return firestore.collection("users").doc(uid).update(data);
}
// Create a new user
export function createUser(uid, data) {
return firestore
.collection("users")
.doc(uid)
.set({ uid, ...data }, { merge: true });
}
/**** ITEMS ****/
/* Example query functions (modify to your needs) */
// Fetch all items by owner (hook)
export function useItemsByOwner(owner) {
return useQuery(
owner && firestore.collection("items").where("owner", "==", owner)
);
}
// Fetch item data
export function useItem(id) {
return useQuery(id && firestore.collection("items").doc(id));
}
// Update an item
export function updateItem(id, data) {
return firestore.collection("items").doc(id).update(data);
}
// Create a new item
export function createItem(data) {
return firestore.collection("items").add(data);
}
/**** HELPERS ****/
// Custom React hook that subscribes to a Firestore query
function useQuery(query) {
const initialState = {
status: "loading",
data: undefined,
error: null,
};
const [state, setState] = useState(initialState);
// Gives us previous query object if query is the same
// ensuring we don't unsubscribe and resubscribe below.
const queryCached = useQueryCache(query);
useEffect(() => {
// Subscribe to query unless falsy, which indicates we're
// waiting on other data needed to construct the query object.
if (queryCached) {
return queryCached.onSnapshot(
(response) => {
// Get data for collection or doc
const data = response.docs
? getCollectionData(response)
: getDocData(response);
setState({
status: "success",
data: data,
error: null,
});
},
(error) => {
setState((state) => ({
status: "error",
data: undefined,
error: error,
}));
}
);
} else {
// Reset back to initial state
if (state.status !== initialState.status) {
setState(initialState);
}
}
}, [queryCached]);
return state;
}
// Get doc data
function getDocData(doc) {
return doc.exists === true ? { id: doc.id, ...doc.data() } : null;
}
// Get array of doc data from collection
function getCollectionData(collection) {
return collection.docs.map((doc) => {
return { id: doc.id, ...doc.data() };
});
}
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;
}