Vue struggles to handle data coming from a composable function

For my specific case, I need to verify whether the user has subscribed to my product through both Stripe and Firebase.

To accomplish this, I created a composable function that checks for the current subscription in the Firebase collection. If the user currently has an active subscription, the function should return the data related to it; otherwise, it should return null.

However, when I invoke the composable function within my Vue component, I am unable to access the returned data as it consistently returns null. Despite seeing the correct value when using console.log(subscription.value) inside the composable function, the Vue component fails to reflect this data accurately.

How can I effectively retrieve and utilize this data within the Vue component?

The composable function:

import { ref } from "vue";
import { db, auth } from "../../firebase/config";
import { collection, query, where, getDocs } from "firebase/firestore";

export function useCurrentSubscription() {

    const isLoading = ref(false);
    const subscription = ref(null);
    const subscriptionType = ref(null);

    async function fetchSubscription() {
        isLoading.value = true;
        const subRef = collection(
            db,
            "stripe-customers",
            auth.currentUser.uid,
            "subscriptions"
        );

        const subQuery = query(
            subRef,
            where("status", "in", ["trialing", "active", "past_due", "unpaid"])
        );

        await getDocs(subQuery).then((sub) => {
            if (sub.docs.length > 0) {
                subscription.value = sub.docs[0];
            } else {
                subscription.value = null;
            }
        });

        if (subscription.value != null) {
            var test = subscription.value.data();
            subscriptionType.value = test.items[0].price.product.metadata.plan;
        }
        isLoading.value = false;

        console.log(subscription.value) //returns the right data
    }

    fetchSubscription();

    return { subscription, isLoading, subscriptionType };
}

The vue component:

<template>
Help World
<template>

<script setup>
import SubscriptionPlansComponent from "../../components/subscriptionPlanComponents/SubscriptionPlansComponent.vue";
import CustomerPortalComponent from "../../components/subscriptionPlanComponents/CustomerPortalComponent.vue";

import { useCurrentSubscription } from "../../composables/stripe/currentSubscription";

const { subscription, isLoading, subscriptionType } = useCurrentSubscription();
console.log(subscription.value); //returns null all the time
</script>

Answer №1

The function fetchSubscription() is asynchronous, which means that the actual data is not set immediately when you call it. This can result in logging a value of null before the data is resolved. Everything seems to be functioning as expected.

To handle this loading delay, you have a couple of options. You could integrate a loading mechanism directly into your component using the isLoading ref that is already being returned. Alternatively, you could modify your composable to return the promise and utilize Vue's built-in suspense feature, which will ensure that the component only renders once the promise has been resolved.

Below is an example demonstrating how to combine suspense with an async component and a composable:

const { createApp, ref } = Vue;

const useAsyncComposable = function(){
  const text = ref('not loaded')
  const load = async () => text.value = await new Promise(resolve => setTimeout(() => resolve('composable has finished loading'), 3000))
  const promise = load()
  return {text, promise}
}

const AsyncComponent = {
  template: '<div>{{ text }}</div>',
  async setup(props, { attrs, slots, emit, expose }) {
    const {text, promise} = useAsyncComposable()
    await promise
    return {text}
  }
}

const App = { 
  components: { AsyncComponent },
}
const app = createApp(App)
app.mount('#app')
<div id="app">
  <suspense>
    <template #default>
        <async-component />
    </template>
    
    <template #fallback>
      <div>Suspense fallback while waiting for async component</div>
    </template>
    
  </suspense>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

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

The translation of popups using ngx-translate in Javascript is not functioning properly

When I click on my request, the content "Are you sure?" is not changing to the required language. This issue is located in list.component.html <button type="button" (click)="myrequest(item.Id)">Request View</button> The fu ...

Translating from JavaScript to Objective-C using JSON

Can someone help me figure out how to correctly 'return' this JSON object in JavaScript? function getJSONData() { var points = '{\"points\": ['; var params = polyline.getLatLngs(); ...

Vue HeadlessUI Error: The function vue.defineComponent is not recognized

Trying to incorporate @headlessui/vue into my nuxt project has been a challenge. My attempt at using it looks like this: <template> <Menu> <MenuItems> <MenuItem>Item</MenuItem> </MenuItems> </Menu&g ...

Make an axios request multiple times equal to the number of items in the previous response

In my project, I am using the axios library to convert addresses into their respective coordinates. First, I fetch a list of addresses from an API. Next, I take the RESPONSE object and use Google API to convert each address to coordinates. Finally, I wan ...

Sequelize Error: The WHERE parameter for 'email' is throwing an error due to an invalid value of 'undefined'

Currently, as part of my Node.js application, I am using Sequelize to develop a user registration feature. However, I seem to be facing an issue when attempting to verify the existence of a user based on their email address. The error that keeps popping up ...

New patch request received in Google Sheets, replacing the existing post request

I am transferring 12 cell values from a Google Sheet to a MongoDB database. The purpose behind this action is to merge the 12 cells, perform certain data transformations, and display the output on a frontend interface later on. Moreover, I'm faced wit ...

Best practice for filling an array using a promise

I am completely new to the world of modern JavaScript. My goal is to fill an array with data that I receive from a promise in a helperService. export class PeopleTableComponent implements OnInit { people: Array < Person > = []; constructor( ...

The issue with Webpack chunking is that no content is appearing because the chunks are not

For the past day, I've been trying to resolve a frustrating yet seemingly simple problem. My goal is to split my bundle.js file into chunks to enhance website loading speed. Below is my webpack.config file: module.exports = { devServer: { historyApi ...

What are the steps to showcase a randomly generated number in a live Flot chart using Json?

In my C# page, I have created a random number stored in a json object: if (method == "rnd") { //Random number this.Page.Response.ContentType = "application/json2"; Random rnd = new Random(); int nr = rnd.Next(1, 100); // generates a number ...

The middleware function encountered an undefined value in req.body

I've been attempting to validate my data retrieved from my express endpoint using yup. Despite watching numerous tutorials, I am encountering a particular error that has me stuck. Every time I try to validate the data in my middleware, it consistentl ...

Challenges with Loading JSON Dynamically in Next.js using an NPM Package

In my TypeScript project, I have implemented a functionality where a json configuration file is dynamically loaded based on an enum value passed as a parameter to the getInstance function in my PlatformConfigurationFactory file. public static async getIn ...

Various relationships in Sails.js

Exploring associations in Sails.js beta (version 0.10.0-rc4) has been quite intriguing for me. My current challenge involves linking multiple databases to produce a unified result (utilizing sails-mysql). The association scheme I'm working with invo ...

Checking for the accuracy of the provided full name

There is a specific task at hand: The field labeled “First Name Last Name” must only contain 2 words, with each word being between 3 and 30 characters in length. Additionally, there should be only one space between the first and last name. The issue t ...

Is there a way to utilize and incorporate Functions from a separate file within an API Server file?

I have integrated ReactJS, Firebase, and React Redux into my project. https://github.com/oguzdelioglu/reactPress Currently, I am displaying data from Firestore by utilizing Functions in https://github.com/oguzdelioglu/reactPress/blob/master/src/services/ ...

Angular input for date is showing wrong value due to timezone problem

My database stores dates in UTC format: this.eventItem.date: "2023-06-21T00:00:00.000Z" The input form field value is showing '2023-06-20' (incorrect day number), which seems to be a timezone issue. I am located in a region with a +3 o ...

Stop Carousel when hovering over individual items (Owl Beta 2)

After creating a unique navigation that is separate from the carousel, I encountered some issues with the autoplay feature. Below is the HTML markup: <div class="carousel"> <div class=""> <img src="assets/img/carousel1.jpg" /&g ...

Break down objects into arrays of objects in JavaScript

Hello, I'm struggling with transforming this object into an array of objects. The 'number' and 'reason' fields are currently stored as strings separated by commas. I need to split them into their own separate objects. The example ...

Collapse the active panel on a jQuery accordion with a click event

I'm currently utilizing the Simple jQuery Accordion created by CSS-Tricks, and I am seeking guidance on how to enable the active panel to close when clicking on the link within the dt element. The scenario where I am implementing this is as a menu in ...

Tips for aligning the first element in an inline-block list item horizontally

I'm working on a list with horizontal scroll functionality to allow users to view content by scrolling. I have successfully implemented this, but I'm facing a couple of challenges that I need help with: I want the first item in the list to alwa ...

Implementing the 'bootstrap tour' feature in a Ruby on Rails application

I have integrated bootstrap-tour.min.css and bootstrap-tour.min.js into my project. <script type="text/javascript" src='bootstrap-tour.min.js'></script> <link rel="stylesheet" type="text/css" href="bootstrap-tour.min.css"> Her ...