salesforce / lwc

⚡️ LWC - A Blazing Fast, Enterprise-Grade Web Components Foundation
https://lwc.dev
Other
1.65k stars 394 forks source link

refreshApex on wired adapter in ERROR-State (property .error supplied) not updating .data or .error on subsequent request #3990

Open t0ng4 opened 10 months ago

t0ng4 commented 10 months ago

Description

When calling refreshApex on an wired adapter that is in an error state (.error property is != undefined) any refreshed/updated response from Apex Call is NOT being assigned to the .error property of the wired property. The .error property keeps the state of the initial error.

This will cause problem when a initially failed apex call is supposed to be repeated (e.g. a external system was temporarily not available/timed out and the user wants to re-try the request).

Steps to Reproduce

  1. Create LWC that wires an @AuraEnabled Apex Controller method that intentionally throws an AuraHandledException right away with current DateTime.now() as Error message:

Apex


public with sharing class ErrorSimulatorController {
    @AuraEnabled(cacheable=true)
    public static String simulateError() {
           AuraHandledException exc = new AuraHandledException(
                'Simple error message: ' + String.valueOf(DateTime.now())
            );
            throw exc;
    }
}

JS

import { LightningElement, wire } from 'lwc';
import { refreshApex } from '@salesforce/apex';
import simulateError from '@salesforce/apex/ErrorSimulatorController.simulateError';

 @wire(simulateError)
    wiredResult; 

handleRefresh() {
     refreshApex(this.wiredResult)
}

get wired() {
    return JSON.stringify(this.wiredResult);
}
  1. Add {wired} output and a button in template that onclick calls handler handleRefresh HTML

    <template>
     <div>
           {wired}
           <div onclick={handleRefresh}></div>
      </div>
    </template>
  2. Click button to refresh wiredAdapter and make call to Apex.

Expected Results

The initial request to simulateError via wiredResult on component creation shows the first timestamp. When refreshing the wiredResult via refreshApex I would expect that the updated error-response from simulateError is provisioned to the wiredResult.error property, indicated by an updated Timestamp showing via {wired} in template.

Actual Results

In chrome dev console I can see the request to Apex is being made and having an updated timestamp in the response. However, the wiredResult.error property keeps the response of the initial request when component was created.

Browsers Affected

Tested with Chrome 121.0.6167.139

nolanlawson commented 9 months ago

Hi @t0ng4, thanks for reporting. If I understand the description correctly, this is an issue with the refreshApex wire, provided by @salesforce/apex, correct? In other words, this issue can only be reproduced when using that wire?

If that's the case, then unfortunately this cannot be solved in this repo (which is for the LWC open-source JavaScript framework). We manage @lwc/wire-service here, but that doesn't seem to be the root cause of your issue.

To resolve your issue most expediently, I would recommend opening a Salesforce Stack Exchange question or a Salesforce case. Providing a reproducible test case (i.e. ZIP file that can be copied into an SFDX repo) would also help.

t0ng4 commented 9 months ago

Hi @nolanlawson, thanks for having a look at the issue. Yes, you understood it correctly. Without that wire refreshApex it is not reproducable as the intial wire call/request provisions both the data and the error property correctly. Thanks for your advice on where to address the issue alternatively. Have nice weekend.

rnordmanASU commented 1 month ago

@t0ng4 Did you end up finding a response on the Stack Exchange or open a Salesforce case? I am seeing the same behavior in my org. Specifically for me, when a wire returns with an error state, attempts to refresh it using refreshApex (even when you can see the Apex is returning a non error state) do not cause the wire function to rerun.

I can verify using my browser's developer tools that the request after the rerun is a non error response (same example code as you but between the initial error run and the supposed-to-succeed rerun I updated simulateError to not throw an error (thus simulating an intermittent issue that a simple rerun fixes).

My original goal was to setup logic for allowing users to reload the failed wires (press a button that runs refreshApex on all failed wires) allowing them to ignore any intermittent errors, but unfortunately after the wire returns an error state the JS wired function stops being called after running refreshApex.

Did you end up getting a response to this issue on the suggested platforms? Or did you find some workaround for your use case?

t0ng4 commented 1 month ago

Hi @rnordmanASU

I didn't pursue the issue further as for my particular use case it was related to a nice-to-have feature, so time trade-off wasn't reasonable.