1
votes

What is the best way to show a loading indicator while retrieving data from Apex in a Lightning Web Component?

I have this approach:

import { LightningElement, api } from "lwc";
import shouldShowCard from "@salesforce/apex/ApexClass.shouldShowCard";

/**
 * Card component that is conditionally shown based on Apex.
 */
export default class ConditionalCard extends LightningElement {
    @api recordId;

    @api isDone = false;

    @api shouldShow = false;

    connectedCallback() {
        shouldShowCard({ id: this.recordId })
            .then(result => {
                this.shouldShow = result;
            })
            .finally(() => {
                this.isDone = true;
            });
    }
}

And this HTML

<template>
  <template if:false={isDone}>
    <div>Loading...</div>
  </template>
  <template if:true={shouldShow>
    <div>Card</div>
  </template>
</template>

Now, this works but I'm using the LWC ESLint rules, and when I do this, I get an error/warning "no-api-reassignment" because I'm assigning the api properties in my connectedCallback. https://github.com/salesforce/eslint-plugin-lwc/blob/master/docs/rules/no-api-reassignments.md

Which seems reasonable, though it very similar to the pattern that the Salesforce Lightning Spinner shows. https://developer.salesforce.com/docs/component-library/bundle/lightning-spinner/documentation

So I'm just looking for advice on the best way to handle this or if I should just disable the ESLint rule. Other things to consider are how to test this stuff, the reactivity with the API decorator has made things pretty easy on my end but I don't want to continue if I'm not using the best approach.

1

1 Answers

1
votes

You don't need @api if these parameters are internal state, if you don't plan to set them from parent component or expose them to System Administrator so he can configure the component in Lightning App Builder for example. You should be fine with just @track - or even no annotation at all. For simple variables you don't need @track since Spring'20 (release notes); you might still need it if your variable is array or object.

This should silence ESLint nicely.

I do it bit differently, personal preference back from Visualforce status and rendered days I guess.

<template>
    <template if:true={loaded}>
        <p>Content goes here</p>
    </template>
    <template if:false={loaded}>
        <lightning-spinner variant="brand" alternative-text="Loading"></lightning-spinner>
    </template>
</template>


import { LightningElement, api, wire, track } from 'lwc';
import someMethod from '@salesforce/apex/SomeClass.someMethod';

export default class StackExample extends LightningElement {
    @api recordId;
    @track data;
    loaded = false;

    @wire(someMethod, { i: '$recordId' }) wiredResponse({ error, data }) {
        if (data) {
            this.data = data;
            // some post-processing here
        } else if (error) {
            // show toast?
        }
        if(data || error){
            this.loaded = true;
        }
    }
}

Remember that some tags like <lightning-datatable> have internal spinner. Search the documentation for isLoading. So you could even not need the ifs in the html.