Lightning @wire adapter deep dive

@wire in Lighting Web Components is a great feature. The most common use case is to connect the result of a backend call to property or method. The other key feature is that using the '$recordId' syntax, the input properties of the wired method are dynamically pushed to the backend.

@wire(getRecord, { recordId: '$recordId', fields: FIELDS })

But what is Decorator?

The Salesforce documentation calls @wire an adapter, and systematically uses the phrase ‘decorate a property or a function’. However, the LWC open-source framework docs calls @wire a decorator. So is it a decorator? Well, it is hard to say.

The problem is that there are no decorators in the Javascript language. Or at least, not at the moment. The decorator idea itself is in proposal phase, and to make things worse, there is an old-experimental and a new-experimental version of this feature.

The proposal is very detailed, so the best way to understand what a decorator should be, is the relatively straightforward Typescript description of the Decorator feature. Long story short, a decorator is a wrapper around a property or a method, which adds additional functionality (for example, @wire pushes automatically some parameters to the backend and gets the result on the decorated property).

But LWC is NOT Typescript. There are decorators in the LWC framework, because it uses internally the Babel transpiler to make available all of the new syntactic sugar like decorators (and it also makes sure, that your code runs in old browsers, too).

@wire anything

Salesforce documentation doesn’t mention it, but in fact you can wire any class to a property or to a method. According to the LWC documentation, all you need to do, is that your class implements the WireAdapter interface. You say there are no interfaces in Javascript? You are right, but who cares at this point? ;)

See this minimalistic example. Any time, you increase num by calling inc(), isq automatically is set to the inverse square root of num. You could make it with a getter too, but here you outsource all the logic to the InvSqrtclass.

And this is the InvSqrt class:

The methods and the constructor follow the WireAdapter interface definition. Anytime a property is changed on the parameters of the wired class, the updatemethod is called. The important thing here is that you decide when to call the callback — so you can write asynchronous logic as well. See the docs here.

Apex and Caching

It worth to mention that Apex returns a data structure which has errorand data properties. They behave the same way as on a ‘simple’ Apex call.

In order to make an Apex Controller method @wire-able, on your Apex class the cacheable property should be set to true: @AuraEnabled(cacheable=true). So if your @wire decorator parameter is set to a previous value, the backend is not called, because the return value is cached.

This saves some bandwidth; however, if your data changed on the server, you can get in trouble. In order to re-push a previous, cached @wire parameter value and get the most recent data, you need use the refreshApex() method. In contrast, client-side wired methods are not cached. You can monitor the caching if you open Chrome DevTools and check the XHR requests on the Network tab. If a value comes from the cache, there is no communication between the server and the browser.

If you look into the call stack and find your generated code, you can see something like this:

Here InvSqrt is a Javascript class, while getTime() is an Apex backend method. Those classes imported very differently:

import { InvSqrt } from ‘c/invSqrt’;

import getTime from ‘@salesforce/apex/myApp.getTime’;

So internally for @wire those two classes are similar. invSqrt.InvSqrt is a JS class import, getTime__default['default'] is an internal wrapper for the Apex callout. They behave the same way from the @wire adapter’s perspective.

Final thoughts

It is hard to find in the code where exactly the client-side caching happens. From the call stack it looks like that the LWC components are handled internally by the Aura framework, which is not open-sourced and subject to change.

So is it safe to use @wire with anything else then the examples from the Salesforce documentation? As the feature is documented in LWC Open Source framework, and it behaves exactly the same way on Salesforce— probably yes.