Component renders before waiting for API Response in Vue.js

I have created two components that depending on a API Response will render either of one of the two components.

  • When the Promise doesn’t resolve or the Promise resolves, but it sends an empty object it renders a error, notification card message.

  • When the Promise resolves, it renders data list component holding the data response.

Now, I got it working properly. However, I have small bug. The error, notification component renders for half a second when there is data on the response. Then, it disappears and the data list renders. Obviously, the component won’t wait for the Promise to evaluate.

Is there a way I could prevent the rendering of component until the Promise is evaluated? Or could you offer me another solutions?

Component that render the data:

<ReferralsList
      ref="referralList"
      v-if="mainSource"
      :service-id="serviceId"
      :source="mainSource"
/>

Component that displays error message:

<Card v-else>
  <template slot="card-content">
    <InlineNotification type="DANGER">
      {{
        The Client Intake module currently does not have any configured referral source.
      }}
    </InlineNotification>
  </template>
</Card>

Promise Data:

created() {
  this.getReferralsSources({ service_id: this.serviceId })
    .then(res => {
      if (res.status >= 200 && res.status < 300) {
        this.sourcesList = res.body;
        this.mainSource = Object.keys(this.sourcesList)[0];
        this.loading_sources = false;
      }
    })
    .catch(() => {
      const message = this.$t('Could not load referrals.');
      this.notifyError(message);
    });
},

That’s not possible, rendering is always a synchronous process.

The split-second rendering is usually misake in how and when the state is set that controls the v-if/v-else

You only show an excerpt of the code in question, you don’t share how the state is initialized in data(), for example which is pretty important here. Cane you share that?

1 Like

Thanks for your reply. Here is the state initialized in data():

data() {
    return {
      sources: {},
      loading_sources: true,
      sourcesList: [],
      mainSource: null,
    };
  },

There we have it.mainSource is initally null, which evaluates to false, which means the v-if is initially false and therefore, the v-else part is rendered.

Solution: use better/correct boolean flags. more speficially, don’t use v-else, use another conditional. You only want to show the error component when two things are true:

  1. the request has finished, and
  2. The request has either failed or does contain an empty object.

so make your condition accordingly:

<Card v-else-if="!loading_sources && !mainSource">
1 Like

That worked thanks!