Creating a function in JavaScript to return an Unsubscribe and Array from a Firebase Snapshot Listener in Svelte

In my SvelteKit project, I have integrated Firebase Firestore. I maintain a db.js file that contains various functions utilized in Svelte components. One such function is detailed below.

export const Items = {
    async getMany() {
        let dbRef = db.collection('items')

        try {
            const snap = await dbRef.get()
            return snap.docs.map(doc => ({ ...doc.data(), id: doc.id }))
        } catch (error) {
            console.log('Error')
        }
    },
}, 

When implementing this function in a Svelte component's onMount lifecycle hook, I fetch the items and assign them accordingly.

let items = []

onMount(() => {
    Items.getMany().then(res => {
       if (res.length !== 0) {
           items = res
       }
    })
})

This setup has been functioning smoothly for me.

Now, I am striving to develop a method within db.js that enables me to utilize a snapshot listener with onSnapshot from Firebase Firestore. My goal is to acquire both the unsubscribe function and the array of items as return values. How can I modify Items.getMany() to deliver both the unsubscribe functionality and an array of items, which I can then set in the Svelte component similar to what is illustrated below?

let items = []
let unsubscribe = function () {
    return
}

onMount(() => {
    Items.getMany().then(res => {
        unsubscribe = res.unsubscribe
        if (res.length !== 0) {
            items = res
        }
    })
})

I've managed to implement this directly within the component and it performs effectively. However, I encounter difficulties when attempting to incorporate it into db.js. Despite experimenting with returning an object containing { unsubscribe, items }, I have not achieved success. Any assistance would be greatly appreciated.

let unsubscribe = function () {
        return
    }
    let items = []

onMount(() => {
        Items.getMany().then(res => {

        let dbRef = db.collection('items')

        unsubscribe = dbRef.onSnapshot(snapshot => {
            items = snapshot.docs.map(doc => ({ ...doc.data(), id: doc.id }))
        })
    })

Answer №1

To retrieve both the unsubscribe function and an array of items from the Items.getMany() function, you can utilize the async/await method.

Here is an example:

async getMany() {
    let dbRef = db.collection('items')

    try {
        const snap = await dbRef.get()
        const items = snap.docs.map(doc => ({
            ...doc.data(),
            id: doc.id
        }))

        // Creating the unsubscribe function
        let unsubscribe = () => {
            dbRef.offSnapshot(snapshot => {
                items = snapshot.docs.map(doc => ({
                    ...doc.data(),
                    id: doc.id
                }))
            })
        }

        return {
            items,
            unsubscribe
        }
    } catch (error) {
        console.log('Error')
    }
},
}

The async/wait approach allows for waiting until the dbRef.get() promise resolves before proceeding with providing the outcome. The getMany() function then constructs the item array from the snap.docs collection.

In the Svelte component, you can utilize the items and unsubscribe variables as demonstrated below:

let items = []
let unsubscribe = null

onMount(async () => {
    const result = await Items.getMany()
    items = result.items
    unsubscribe = result.unsubscribe
})

onDestroy(() => {
    if (unsubscribe) {
        unsubscribe()
    }
})

For more information on the Async/Await method, you can refer to: Understanding How Async/Await Works in JavaScript

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Hiding a pop-up element and updating the state to False when clicking anywhere outside the element in the background

Presented here is my Search.js component. class Search extends Component { state = { doctors: [], showTab: false } openTab = () => { this.setState({showTab: true}); console.log('openTab state', this ...

Search for spaces and brackets in a file name, excluding the file extension using Regular Expressions

Currently utilizing javascript and I have a specific string let filename1 = "excluder version(1).pdf" Keep in mind that the extension may vary, like jpg or png I am looking to replace the original string with the desired outcome is it possible ...

Utilizing References in React Components

One of the challenges I am facing involves a Container that needs references to some of its child components: const Container = () => { const blocks: HTMLDivElement[] = []; return ( <div> <Navigation currentBlock={currentBlock} ...

Guide on creating a custom type for an object utilizing an enum framework

Enumerating my shortcuts: export enum Hotkey { MARK_IN = 'markIn', MARK_OUT = 'markOut', GO_TO_MARK_IN = 'goToMarkIn', GO_TO_MARK_OUT = 'goToMarkOut' } I am now looking to define a type for a JSON ob ...

Having trouble shutting down Metro Bundler on Windows?

While working on my React Native development, I regularly use npm start to get things going. However, I've run into an issue recently when trying to stop the process using Ctrl + c. It seems like I can no longer use npm start smoothly: ERROR Metro ...

Interacting with APIs using jQuery, managing responses with AJAX, handling parsererror in our development environment XAMPP on Windows 8

I've come across numerous questions regarding the dreaded "parsererror" but I just can't seem to find a solution that fits my specific issue. Here's the code causing me grief: <!DOCTYPE html> <html> <head> <meta http-eq ...

Tips for successfully retrieving a span value in VUE

I am working with forms <input type="text" v-model="email"> <span>Extracted Value</span> Can someone help me figure out how to pass the value from the span element? data () { return { email: '/*Here goes the extracted valu ...

Show react-card-flip children conditionally based on a button, otherwise display one frontside and two backsides

Is it possible to achieve the following functionality using the react-flip-package? I have a card with two buttons on the front side. When I click one button, I want the card to flip to one backside, and when I click the other button, I want it to flip to ...

Tips on uploading multiple images to Firebase Storage and retrieving multiple downloadURLs

Currently, we are in the process of developing a straightforward e-commerce application that requires uploading multiple product images. By utilizing Vuejs and Vue-Croppa, our objective is to upload these images to Firebase storage, retrieve their download ...

Activating the change event in jQuery: A step-by-step guide

Within my ASP.NET page, I have included a UserControl that contains a RadioButtonList. Whenever an item in the RadioButtonList is changed, I need to trigger the following jQuery function: $('#rdlUser').change(function (e) { alert("change fun ...

Failed commitments in JavaScript without a catch block (unhandled rejection)

When working on my project in VueJs JavaScript, I want to be able to see console messages if any of my Promises are not fulfilled and do not have a catch block. I attempted using the following code: Promise.reject("error!"); window.addEventListener(&apos ...

What is the best way to incorporate a search bar into a dropdown menu?

Would someone be able to assist me in adding a search bar as the primary value of the dropdown menu? I am using ASP.NET MVC and this is my current code snippet. <div class="col-md-8"> <div class="dropdown"> <div class="chzn-d ...

I am looking to include a popover within my modal using Bootstrap version 3.0.2

Hey there, I'm having an issue where the popover that should be inside the modal is actually appearing outside of it in the top left corner, not visible within the modal itself. Below is my index code: <button type="button" id="example" class="bt ...

Create dynamic automatic titles in HTML with JavaScript

Below is the code snippet to add an image with a link to the home-page and an h1 with the document name (if there isn't one already). This HTML code includes a JavaScript file reference in the <head> section and uses a <h1> tag for the ti ...

Encountering the 'navigator is not defined' error when attempting to generate a Next JS build

After developing a custom hook in Next JS to retrieve network online status using the JavaScript navigator.onLine property, everything seemed to work flawlessly on my local machine. However, upon running npm run build to compile the project, I encountered ...

Unexpected glitch: three.js texture turns completely black

I am currently working on a simple geometry box that I want to decorate with a texture. However, the box seems to be invisible or completely black. This issue is related to a previous question that can be found here. Following the answer provided by gaitat ...

Confirmed the validation of an input that falls outside the parameters of the ReactiveForms model

Check out this StackBlitz example In my Angular application, I am utilizing a Reactive form with 3 inputs, each having its own validation. Additionally, there is an input that exists outside of the form within its own component, also with its own reactive ...

Issue with back button functionality when loading page with history.pushState in JavaScript

My current issue involves loading a page via ajax using history.pushState. The page loads successfully, but the back button does not work as expected. I have included my code below for reference: function processAjaxData(response, urlPath){ document.wr ...

Does the onChange event fire when the value is modified by the parent element?

let [number, set_number] = useState({x: 1}); <ChildComponent number={number} onUpdate={onUpdateFunction} </ChildComponent> set_number({x: 2}) After running set_number({x: 2}), will this action prompt the execution of onUpdateFunction refere ...

What is the best way to set conditions for document side script?

I'm struggling to disable the horizontal scroll when the viewport width is 480px or less. The script that controls the scroll behavior on my website looks like this: <script> $(function () { $("#wrapper").wrapInner("< ...