ApexSensei

Apex

Read with a cacheable @wire, save with an imperative call, and use the UI API when you do not need a custom Apex class.

A cacheable wire for a read

Mark a read method @AuraEnabled(cacheable=true). It must be public or global, and static. A cacheable method cannot insert, update, or delete.

Import it from @salesforce/apex/AccountList.recent and decorate a field with @wire. The result has data and error. A client cache is checked before the network call. Call refreshApex when that cached read is stale. Lightning Data Service does not manage rows that Apex returned.

An imperative call for a change

Call the method yourself when the person saves. Leave cacheable=true off a method that changes data. The import returns a promise: await rename({ accountId, name }).

Pass arguments as one object whose keys match the Apex parameter names. A Map is not a supported argument. Use try/catch around the await. You also call imperatively when you need to choose the moment, or when the object is outside the UI API, such as Task and Event.

Skip Apex when the UI API fits

To read one record the user can already open, wire getRecord from lightning/uiRecordApi. Pass recordId and the fields. getFieldValue reads a field off the result.

To query with a filter, use the GraphQL wire adapter. Import graphql from lightning/graphql when you can. lightning/uiGraphQLApi still works, and it does not cover the newer features. Both follow the user's object and field access, so a plain read does not need a custom Apex class.

Example

apex

public with sharing class AccountList {
    @AuraEnabled(cacheable=true)
    public static List<Account> recent() {
        return [
            SELECT Id, Name
            FROM Account
            WITH USER_MODE
            ORDER BY CreatedDate DESC
            LIMIT 20
        ];
    }

    @AuraEnabled
    public static void rename(Id accountId, String name) {
        update as user new Account(Id = accountId, Name = name);
    }
}