Introduction
One of the things I particularly like about Lightning Web Components is the wire service. The ability to let the platform send me the data when it decides things are ready, rather than having to figure out when to call an Apex method based on rendered callbacks and the like really cleaned up my code from the days of Aura.
Updated Records on the Server
The one area that it doesn't automatically handle for me is sending me new data when a record is updated server side, by other Apex code or maybe the controller of the LWC that is using the wire service. Initially my approach was to return the updated records to the component if it was my own controller method carrying out the update, or switch to imperative Apex calls once I knew an update had taken place. Neither of these were particularly satisfactory though.
The solution is the refreshApex method, which you import from salesforce/apex. Per the docs
Sometimes, you know that the cache is stale. If the cache is stale, the component needs fresh data. To query the server for updated data and refresh the cache, import and call the refreshApex() function.
Exactly what I need, and it keeps my data in the scope of the wire service, so if that gets notified that there is a newer version of the data, I'll get that too.
There's a slight gotcha that makes it easy to get this wrong. When I first tried it I was convinced that it didn't work, because I'd misunderstood a key aspect of the docs. The instruction in question is:
So in my wire method handler, I captured the object that I'd retrieved:NOTE The parameter you refresh with refreshApex() must be an object that was previously emitted by an Apex @wire.
@wire(GetPage, {name: 'home'}) gotPage(result) { if (result.data) { this.page=result.data; this.dataToRefresh=result.data; }
and when I knew the record had been updated server side, I executed the refreshApex method:
getLatest() { refreshApex(this.dataToRefresh); }
getLatest() { refreshApex(this.dataToRefresh) .then(()=> { this.dispatchEvent( new ShowToastEvent({ title: 'Success', message: 'Refreshed Data', variant: 'success' }) ); }) .catch((error) => { this.dispatchEvent( new ShowToastEvent({ title: 'Error Refreshing Data', message: message, variant: 'error' }) ); }); }
this time I got an error, that didn't make a lot of sense to me, but seemed like the refreshApex method wasn't returning a promise, even though it was supposed to return an promise.
As it was the first time I'd used it, I had no idea what the correct usage looked like, so there was a bit of trial and error before I realised that "an object that was previously emitted by an Apex @wire" meant the entire object rather than the data property that I was extracting. And reading further on the docs confirmed this, which reminded me to always RTFM!
Updating my wire method handler to capture the whole thing rather than the records from the server:
@wire(GetPage, {name: 'home'}) gotPage(result) { if (result.data) { this.page=result.data; this.dataToRefresh=result; }
Hello,
ReplyDeleteThank you for sharing this.
I've read the docs and multiple articles and blogs and I'm doing exactly the same i.e. I'm passing the entire object returned by wire to refreshApex method but it's still not working.
My table has infinite scrolling enabled and it doesn't directly show the data returned from wire instead I need to process the data save it in a different array and then display it on the table.
Could you please suggest if I need to do anything extra for this to work for me as well?
Thanks!