Skip to content

Commit d8a9339

Browse files
committed
Add link to SWR Firestore
1 parent 5f3a3d2 commit d8a9339

File tree

1 file changed

+3
-0
lines changed

1 file changed

+3
-0
lines changed

src/pages/useFirestoreQuery.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ links:
99
- url: https://github.com/tannerlinsley/react-query
1010
name: React Query
1111
description: Data fetching library that has a similar useQuery hook and inspired the API for this example.
12+
- url: https://github.com/nandorojo/swr-firestore
13+
name: SWR Firestore
14+
description: Firestore query hooks built on top of SWR
1215
code: "\/\/ Usage\r\nfunction ProfilePage({ uid }) {\r\n \/\/ Subscribe to Firestore document\r\n const { data, status, error } = useFirestoreQuery(\r\n firestore.collection(\"profiles\").doc(uid)\r\n );\r\n \r\n if (status === \"loading\"){\r\n return \"Loading...\"; \r\n }\r\n \r\n if (status === \"error\"){\r\n return `Error: ${error.message}`;\r\n }\r\n\r\n return (\r\n <div>\r\n <ProfileHeader avatar={data.avatar} name={data.name} \/>\r\n <Posts posts={data.posts} \/>\r\n <\/div>\r\n );\r\n}\r\n\r\n\/\/ Reducer for hook state and actions\r\nconst reducer = (state, action) => {\r\n switch (action.type) {\r\n case \"idle\":\r\n return { status: \"idle\", data: undefined, error: undefined };\r\n case \"loading\":\r\n return { status: \"loading\", data: undefined, error: undefined };\r\n case \"success\":\r\n return { status: \"success\", data: action.payload, error: undefined };\r\n case \"error\":\r\n return { status: \"error\", data: undefined, error: action.payload };\r\n default:\r\n throw new Error(\"invalid action\");\r\n }\r\n}\r\n\r\n\/\/ Hook\r\nfunction useFirestoreQuery(query) {\r\n \/\/ Our initial state\r\n \/\/ Start with an \"idle\" status if query is falsy, as that means hook consumer is\r\n \/\/ waiting on required data before creating the query object.\r\n \/\/ Example: useFirestoreQuery(uid && firestore.collection(\"profiles\").doc(uid))\r\n const initialState = { \r\n status: query ? \"loading\" : \"idle\", \r\n data: undefined, \r\n error: undefined \r\n };\r\n \r\n \/\/ Setup our state and actions\r\n const [state, dispatch] = useReducer(reducer, initialState);\r\n \r\n \/\/ Get cached Firestore query object with useMemoCompare (https:\/\/usehooks.com\/useMemoCompare)\r\n \/\/ Needed because firestore.collection(\"profiles\").doc(uid) will always being a new object reference\r\n \/\/ causing effect to run -> state change -> rerender -> effect runs -> etc ...\r\n \/\/ This is nicer than requiring hook consumer to always memoize query with useMemo.\r\n const queryCached = useMemoCompare(query, prevQuery => {\r\n \/\/ Use built-in Firestore isEqual method to determine if \"equal\"\r\n return prevQuery && query && query.isEqual(prevQuery);\r\n });\r\n\r\n useEffect(() => {\r\n \/\/ Return early if query is falsy and reset to \"idle\" status in case\r\n \/\/ we're coming from \"success\" or \"error\" status due to query change.\r\n if (!queryCached) {\r\n dispatch({ type: \"idle\" });\r\n return;\r\n }\r\n \r\n dispatch({ type: \"loading\" });\r\n \r\n \/\/ Subscribe to query with onSnapshot\r\n \/\/ Will unsubscribe on cleanup since this returns an unsubscribe function\r\n return queryCached.onSnapshot(\r\n response => {\r\n \/\/ Get data for collection or doc\r\n const data = response.docs\r\n ? getCollectionData(response)\r\n : getDocData(response);\r\n \r\n dispatch({ type: \"success\", payload: data });\r\n },\r\n error => {\r\n dispatch({ type: \"error\", payload: error });\r\n }\r\n );\r\n \r\n }, [queryCached]); \/\/ Only run effect if queryCached changes\r\n\r\n return state;\r\n}\r\n\r\n\/\/ Get doc data and merge doc.id\r\nfunction getDocData(doc) {\r\n return doc.exists === true ? { id: doc.id, ...doc.data() } : null;\r\n}\r\n\r\n\/\/ Get array of doc data from collection\r\nfunction getCollectionData(collection) {\r\n return collection.docs.map(getDocData);\r\n}"
1316
---
1417

0 commit comments

Comments
 (0)