{
    "componentChunkName": "component---src-templates-post-js",
    "path": "/blog/fetching-data-from-firestore/",
    "result": {"data":{"site":{"siteMetadata":{"title":"Danniel Hansel"}},"mdx":{"id":"b15e2892-c0b8-5bbc-966d-3bfb10cac6c2","excerpt":"This quick guide shows you how to fetch data from Cloud Firestore. Assuming you already have a collection with a list of documents. Note: This guide will use…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"fetching-data-from-firestore\",\n  \"title\": \"Fetching data from Firestore\",\n  \"date\": \"2021-11-08\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"This quick guide shows you how to create a React custom hook to fetch data from Cloud Firestore.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"database\"],\n  \"tags\": [\"react\", \"ssr\", \"database\", \"nextjs\", \"database\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602322/dannielhansel.com/content/blog/fetching-data-from-firestore_zalbof.jpg\",\n  \"bannerCredit\": \"Photo by [Tobias Fischer](https://unsplash.com/photos/PkbZahEG2Ng) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `This quick guide shows you how to fetch data from Cloud Firestore. Assuming you already have a collection with a list of documents.`), mdx(\"p\", null, `Note: This guide will use Web version 9 (modular) - which is the latest version.`), mdx(\"h1\", null, `What we are going to do in this tutorial:`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Understand how Event Sourcing & Event Streams work.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Understand how Snapshots work.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Create a React custom hook which listens to events from Firestore Database.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Render our data in our component.`)), mdx(\"p\", null, `If you don't have a project set up yet on Firebase, I have this `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/blog/initial-setup-for-cloud-firestore-database/\"\n  }, `quick guide`), ` to help you set it up.`), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, `💡 Once we've initialized our Firestore database, we will need it here.`)), mdx(\"h1\", null, `Event Sourcing & Streams`), mdx(\"p\", null, `In Event Sourcing, you'll typically replay all the events from the beginning of time from an Event Stream to get to the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `current state`), ` of your aggregate. In most occasions, you'll have a `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `lifecycle`), ` to the stream that will eventually end but you could also have a stream that is never ending, something like products in a warehouse. The problem is what if we have thousands or millions of events that need to be replayed? This will create a very inefficient, time-consuming and slow process 😐 . This is where Snapshots come in.`), mdx(\"h1\", null, `Snapshots`), mdx(\"p\", null, `A snapshot is a representation of state for your aggregate at a particular point in time or event. To `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://firebase.google.com/docs/firestore/query-data/listen\"\n  }, `get realtime updates`), ` with our Cloud Firestore database, we will need an `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `onSnapshot()`), ` method which listens to a document. When you provide a callback in the initial call, it creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot. To listen to multiple documents in a collection, this method will listen to the results of a query which then creates a query snapshot.`), mdx(\"h1\", null, `React Custom Hook`), mdx(\"p\", null, `In order fetch and render the most updated data from our Firestore Database onto our UI, we will need to create a custom hook. This hook's job is to listen to events from our database, record the state of the aggregate and store the state. By using `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `onSnapshot()`), ` method, it attaches a listener for `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `QuerySnapshot`), ` events in our Firebase. Note that although streams are never ending, this listener can be cancelled by calling the function that is returned when `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `onShapshot()`), ` is called.`), mdx(\"h2\", null, `Explanation`), mdx(\"p\", null, `We will store the snapshot in an array using the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `useState hook`), `. To be able to detect changes, we will use the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `useEffect hook`), ` with our collection as dependency so that every document change in our collection gets hooked and stored in our state. The job of `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `collection()`), ` method here is to get the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `CollectionReference`), ` instance that refers to the collection at the specified absolute path and returns the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `CollectionReference`), ` instance.`), mdx(\"h2\", null, `Code`), mdx(\"p\", null, `Create a folder `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `\"hooks\"`), ` inside src and create a file `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `\"useFirestore.js\"`), `:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `mkdir root/src/hooks\ntouch root/src/hooks/useFirestore.js\n`)), mdx(\"p\", null, `Stick this code in it:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `import { useEffect, useState } from \"react\" // import the React hooks\nimport { onSnapshot, collection } from \"firebase/firestore\" // import the methods from firestore\nimport { firestoreDb } from \"../config/firebase\" // The reference to our Firestore database after we've initialized it.\n\nexport const useFirestore = col => {\n  const [docs, setDocs] = useState([])\n\n  useEffect(\n    () =>\n      onSnapshot(collection(firestoreDb, col), snapshot =>\n        setDocs(snapshot.docs.map(doc => ({ ...doc.data(), id: doc.id })))\n      ),\n    [col]\n  )\n\n  return { docs }\n}\n`)), mdx(\"h1\", null, `Render your data`), mdx(\"p\", null, `Create a file \"`, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Products.js`), `\" inside `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `src/components`), `.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `touch src/components/Products.js\n`)), mdx(\"p\", null, `Then, copy this code in it:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `import { useFirestore } from \"../hooks/useFirestore\" // Our hook we just created\n\nconst Products = () => {\n  const { docs } = useFirestore(\"your-collection-name\") // Our hook takes in the collectionName as parameter\"\n\n  return (\n    <div>\n      // ... add your own styling here\n      <ul>\n        {docs.map((product, index) => {\n          return (\n            <li key={index} className=\"flex my-2\">\n              <p>{index + 1}</p>\n              <h1>{product.Name}</h1> // Grab the keys from your document fields\n              <p>{product.Description}</p>\n              <p>\\${product.Price}</p>\n            </li>\n          )\n        })}\n      </ul>\n    </div>\n  )\n}\nexport default Products\n`)), mdx(\"p\", null, `Lets go ahead and run the app:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `npm run dev\n`)), mdx(\"p\", null, `Voila! We can now fetch our data from Cloud Firestore database. 👏`), mdx(\"p\", null, `While there is another option to fetch data from Firebase (like `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.npmjs.com/package/react-firebase-hooks\"\n  }, `react-firebase-hooks`), `), I chose to create my own customized hook that is understandable to me and works for me.`), mdx(\"p\", null, `If you are interested to learn more on how to sort & update the data from Firestore or how to store & delete images from Firebase Storage, check out my other blog posts. Good luck!`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":2,"fields":{"slug":"/blog/fetching-data-from-firestore/"},"frontmatter":{"slug":"fetching-data-from-firestore","title":"Fetching data from Firestore","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602322/dannielhansel.com/content/blog/fetching-data-from-firestore_zalbof.jpg","bannerCredit":"Photo by [Tobias Fischer](https://unsplash.com/photos/PkbZahEG2Ng) on [Unsplash](https://unsplash.com)","tags":["react","ssr","database","nextjs","database"],"description":"This quick guide shows you how to create a React custom hook to fetch data from Cloud Firestore.","date":"November 08, 2021"}},"relatedMdxs":{"posts":[{"id":"f2db5aef-b482-532f-9a92-f93463cc0a26","timeToRead":2,"slug":"blog/the-debate-between-library-vs-package-vs-framework-vs-module","frontmatter":{"title":"The Debate between Module vs Package vs Library vs Framework","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453749/dannielhansel.com/content/blog/package-library_xqm8ix.webp","bannerCredit":"Photo by [Bench Accounting](https://unsplash.com/photos/MGaFENpDCsw) on [Unsplash](https://unsplash.com)","slug":"the-debate-between-library-vs-package-vs-framework-vs-module","tags":["software-engineering","tools"],"description":"One of the most frequent asked question in Software Engineering.","date":"January 10, 2021"}},{"id":"1bd58e0e-11af-50e2-b16f-1284d82c7cea","timeToRead":7,"slug":"blog/7-basic-rules-for-self-improvement","frontmatter":{"title":"7 Basic Rules for Self Improvement","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602245/dannielhansel.com/content/blog/7-basic-rules-for-self-improvement_vhqngn.jpg","bannerCredit":"Photo by [Alif Ngoylung](https://unsplash.com/photos/-A_Sx8GrRWg) on [Unsplash](https://unsplash.com)","slug":"7-basic-rules-for-self-improvement","tags":["personal","productivity"],"description":"What I have learned from doing self-development work.","date":"November 27, 2020"}},{"id":"edc10d92-c4e5-58c7-a0ec-e0a4fb636181","timeToRead":5,"slug":"blog/powerful-morning-routines-that-will-change-your-life","frontmatter":{"title":"Powerful Morning Routines that Will Change Your Life","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639601696/dannielhansel.com/content/blog/rebuilding-my-portfolio-site-with-tailwind-css_rqnsbb.jpg","bannerCredit":"Photo by [lucas Favre](https://unsplash.com/photos/JnoNcfFwrNA) on [Unsplash](https://unsplash.com)","slug":"powerful-morning-routines-that-will-change-your-life","tags":["personal","productivity"],"description":"Killer morning routines to better your life and reach your full potential.","date":"February 03, 2021"}},{"id":"6716a85b-6801-525e-b2ea-5448c01bf60d","timeToRead":6,"slug":"blog/rebuilding-my-portfolio-site-with-tailwind-css","frontmatter":{"title":"Rebuilding my portfolio site with Tailwind CSS","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453752/dannielhansel.com/content/blog/rebuild-portfolio_s7cuq0.webp","bannerCredit":"Photo by [Aziz Acharki](https://unsplash.com/photos/6YpwRf0iUa4) on [Unsplash](https://unsplash.com)","slug":"rebuilding-my-portfolio-site-with-tailwind-css","tags":["javascript","react","gatsby","tailwind-css","bootstrap"],"description":"My experience with Tailwind CSS.","date":"May 13, 2021"}},{"id":"607bdcda-0d6c-5f06-9a34-7c59aca6989d","timeToRead":1,"slug":"blog/initial-setup-for-cloud-firestore-database","frontmatter":{"title":"Initial setup for Cloud Firestore database","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602371/dannielhansel.com/content/blog/initial-setup-for-cloud-firestore-database_p8rflb.jpg","bannerCredit":"Photo by [Jan Antonin Kolar](https://unsplash.com/photos/lRoX0shwjUQ) on [Unsplash](https://unsplash.com)","slug":"initial-setup-for-cloud-firestore-database","tags":["react","ssr","backend","nextjs","database"],"description":"This quick guide shows you how to set up Cloud Firestore for your React application.","date":"November 01, 2021"}},{"id":"cf047db2-ca90-5b7d-85d4-62dd9bec16bd","timeToRead":2,"slug":"about/about-me","frontmatter":{"title":"About Danniel Hansel","author":"Danniel Hansel","bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":"Learn about Danniel Hansel and how he got to where he is","date":null}},{"id":"f5e43818-6b9e-539f-b958-b022a7c84719","timeToRead":2,"slug":"blog/image-types-vector-vs-pixel","frontmatter":{"title":"Image types: Vector vs. Pixel","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1644037300/dannielhansel.com/content/blog/pixal-vs-vector_dkaxg1.jpg","bannerCredit":"Photo by [Umberto](https://unsplash.com/photos/deb2EnbWPr8) on [Unsplash](https://unsplash.com)","slug":"image-types-vector-vs-pixel","tags":["performance"],"description":"Why you should go for Vector vs. Pixel.","date":"December 03, 2021"}},{"id":"b86814e4-5866-5e31-91ff-d0a8b9ea363b","timeToRead":1,"slug":"blog/handling-external-links-for-mdx-files-in-gatsby","frontmatter":{"title":"Handling External Links for MDX files in Gatsby","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453751/dannielhansel.com/content/blog/external-link_roctbf.webp","bannerCredit":"Photo by [Eric Mclean](https://unsplash.com/photos/sxiSod0tyYQ) on [Unsplash](https://unsplash.com)","slug":"handling-external-links-for-mdx-files-in-gatsby","tags":["ssg","react","gatsby"],"description":"The easiest way to open links in a new tab when using gatsby-plugin-mdx.","date":"December 10, 2021"}},{"id":"f3c648a6-01ba-585b-99f5-85cf76a54f73","timeToRead":1,"slug":"testimonial/testimonial","frontmatter":{"title":"Testimonial 1","author":"Maggie","bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":null,"date":null}},{"id":"4e777b1c-f8d9-57f8-9799-cfd6f1af27a2","timeToRead":1,"slug":"about/about","frontmatter":{"title":"About Me","author":"Danniel Hansel","bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":"Learn about Danniel Hansel and what he does","date":null}},{"id":"23fb515e-31a0-5407-b16b-d9b688f2b5af","timeToRead":1,"slug":"blog/updating-data-from-firestore","frontmatter":{"title":"Updating data from Firestore","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602451/dannielhansel.com/content/blog/updating-data-from-firestore_zvsbav.jpg","bannerCredit":"Photo by [Piron Guillaume](https://unsplash.com/photos/U4FyCp3-KzY) on [Unsplash](https://unsplash.com)","slug":"updating-data-from-firestore","tags":["react","ssr","database","nextjs","backend"],"description":"This quick guide shows you how to handle CRUD operations from Firestore database.","date":"November 27, 2021"}},{"id":"c63edb7e-453e-5bac-ab79-6514bfcc5983","timeToRead":1,"slug":"project/project10/project10","frontmatter":{"title":"Book List Tracker","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"57e4f42a-2bfd-5fde-b040-2907d11a5ea5","timeToRead":1,"slug":"hero/hero","frontmatter":{"title":"Danniel Hansel","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":null,"date":null}},{"id":"6f5b7bcc-efa4-5084-8b34-cec1b0506f16","timeToRead":1,"slug":"blog/my-favorite-tech-podcasts","frontmatter":{"title":"My Favorite Tech Podcasts","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1644037050/dannielhansel.com/content/blog/my-favorite-podcasts_ksnqce.jpg","bannerCredit":"Photo by [Mohammad Metri](https://unsplash.com/photos/1oKxSKSOowE) on [Unsplash](https://unsplash.com)","slug":"my-favorite-tech-podcasts","tags":["personal","productivity"],"description":"I've compiled a list of my favorite tech and non-tech podcasts.","date":"January 15, 2022"}},{"id":"63959d00-7675-5872-abd4-3ace45480a22","timeToRead":1,"slug":"project/project9/project9","frontmatter":{"title":"Budget Calculator","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"e8a491a4-73b5-5be8-b294-49362cf66dc0","timeToRead":1,"slug":"project/project3/project3","frontmatter":{"title":"E-Commerce Web App","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["React","Material UI","Commerce.js","Stripe"],"description":null,"date":null}},{"id":"6563d4b8-ff14-5280-8e20-7f7b930b8f73","timeToRead":1,"slug":"project/project1/project1","frontmatter":{"title":"The Crab Station & Oyster Bar","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["React","GatsbyJS","Bootstrap","Contentful","Netlify","AWS"],"description":null,"date":null}},{"id":"57c19c65-eeb5-5d52-ae1f-c83b4caef2ff","timeToRead":1,"slug":"project/project2/project2","frontmatter":{"title":"Smart POS Web App","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["React","NextJS","Tailwind","Firebase","Firestore","NodeJS","OpenShift"],"description":null,"date":null}},{"id":"1811b711-5e38-548f-ad4e-5e774b0f2a00","timeToRead":1,"slug":"project/project11/project11","frontmatter":{"title":"Accordion UI","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"a4e7f4fe-a19d-5cf5-86fd-149edddafdc3","timeToRead":1,"slug":"project/project6/project6","frontmatter":{"title":"Todos App","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"0f9e61b3-88a9-5ea1-b965-0098a1061015","timeToRead":1,"slug":"project/project4/project4","frontmatter":{"title":"Type Racer","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","Bootstrap"],"description":null,"date":null}},{"id":"875cf1c0-a200-5715-9d26-d0cdd74aea7b","timeToRead":1,"slug":"project/project8/project8","frontmatter":{"title":"Quote Generator v2","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"c34b3f70-bf92-5a5f-9d18-90fb40c407aa","timeToRead":1,"slug":"project/project5/project5","frontmatter":{"title":"Tic Tac Toe","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"d6c51e86-ed84-5489-a9f8-0f38e78963b2","timeToRead":1,"slug":"project/project7/project7","frontmatter":{"title":"Quote Generator v1","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}}]}},"pageContext":{"id":"b15e2892-c0b8-5bbc-966d-3bfb10cac6c2"}},
    "staticQueryHashes": ["2744905544","3145194271","3970664207"]}