Salesforce gives you more than one way to call an Apex method from a Lightning Web Component (LWC). Here are three of them, what each one costs you, and a code example for each.

1. Calling Apex methods using @wire
The @wire decorator handles soql-returns-old-value-after-ui-update/" class="auto-link">data retrieval for you, and the component updates on its own whenever the underlying data source changes. The code stays short enough to read in one go.
What you give up: each wire decorator gets you one Apex method call, and you cannot perform complex business logic in the component.
A wired call looks like this:
import { LightningElement, wire } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContacts';
export default class ContactList extends LightningElement {
@wire(getContacts) contacts;
}
2. Calling Apex methods imperatively
An imperative call gives you more control over the flow of the code, so you can perform complex business logic in the component, and you can call several Apex methods from the same component.
The cost is plumbing. Nothing handles the data retrieval or the updates for you, and the code gets more verbose and harder to follow.
Here is the same fetch, done imperatively:
import { LightningElement } from 'lwc';
import getContacts from '@salesforce/apex/ContactController.getContacts';
export default class ContactList extends LightningElement {
contacts;
connectedCallback() {
getContacts()
.then(result => {
this.contacts = result;
})
.catch(error => {
console.error(error);
});
}
}
3. Calling Apex methods with parameters
Passing parameters to an Apex method is a common requirement, and you can do it with the @wire decorator or with an imperative call. It makes the code more flexible, and there is no real disadvantage to it.
In this example the account id comes from user input and gets passed into the wired call:
import { LightningElement, wire } from 'lwc';
import getContactsByAccountId from '@salesforce/apex/ContactController.getContactsByAccountId';
import { getRecord } from 'lightning/uiRecordApi';
export default class ContactList extends LightningElement {
accountId;
contacts;
@wire(getRecord, { recordId: '$accountId', fields: ['Account.Name'] })
account;
handleAccountIdChange(event) {
this.accountId = event.target.value;
}
@wire(getContactsByAccountId, { accountId: '$accountId' })
wiredContacts({ error, data }) {
if (data) {
this.contacts = data;
} else if (error) {
console.error(error);
}
}
get hasResults() {
return this.contacts && this.contacts.length > 0;
}
}
Conclusion
Which one fits depends on the use case. The @wire decorator is the one to reach for in most situations, because it handles the data retrieval and updates the component when the data changes. Imperative calls, with or without parameters, give you more flexibility and control, and cost you some readability in return.
Leave a Comment