3

I have observed something really weird for which I haven’t found an explanation yet. I have a component (parentComponent) containing a subcomponent (childComponent).

The childComponent subcomponent has a @wired function retrieving data from the database, which is working correctly when childComponent is loaded:

@wire(myServerMethod, {param: '$myParamProperty'})
myWiredFunction(result) {
   if (result.data) {
      this.myWiredProperty = result;
      console.log(‘Got the response from the server’);
      ...
}

myWiredFunction is returning the data from the server as expected, and I put result in a private property (myWiredProperty) so that I can call refreshApex later. So far so good.

When the user does something in the parentComponent, we want the childComponent to refresh the data from the database. For that, the parentComponent wants to pass a new value to the childComponent, which will be used in the @wired function to retrieve the data. So we pass the new value from the parentComponent to the childComponent to put it in myParamProperty, which is wired to the wired function and made reactive as can be seen: {param: ‘$myParamProperty’}

I could pass the new value from the parentComponent to the childComponent through a public property and use reactivity, I know, but for now I am forcing the property refresh through a public function that childComponent is exposing, and which parentComponent is calling imperatively when it wants childComponent to re-query the data from the database.

In parentComponent:

this.template.querySelector('c-child-component).refreshProperty(this.value);

In childComponent:

@api
refreshProperty(newValue) {
   this.myParamProperty = newValue;
   refreshApex(this.myWiredProperty);
}

So, if I update myParamProperty and then call refreshApex, that in theory should re-query the data through the wired function using the new value passed as the parameter.

Well, this is not working as expected. I may be overlooking something obvious, but if I check the value in myParamProperty just before calling refreshApex, I can see the new value as expected. Then refreshApex makes the wired function myWiredFunction to be re-invoked as expected, but the result returned by the LDS is the same as it was before, which means that nothing inside the wired function is run (i.e. the promise containing the console log with ‘Got the response from the server’ is not run).

So the wired function will not be run if the cache returns the same value we had before, but why is it returning the same result if I am passing a different parameter (myParamProperty)? Should that not make the cache/server return a different value?

As I can see the logs on the server side, in the Apex method, the first thing a do is inspect the value being received from the client. And here is my surprise: the value received by the server is the value of myParamProperty before it was updated.

That explains why the server is not returning a different result, but why is the property value lost in the communication between the client and the server?

So in summary:

  1. I inspect the value of myParamProperty → it contains the new value as expected.
  2. I call refreshApex → the wired function is re-invoked.
  3. I check the logs on the server side → the parameter received is the old value.

I have a workaround which is working consisting of calling the same Apex method through an imperative call from JS. In this case the property is being sent to the server correctly and everything works as expected, but feels like a redundant solution when I have the wired function retrieving the data correctly the first time.

Apologies for the long post, I hope I have explained everything clearly! I would appreciate any thoughts, thanks!

1
  • Welcome to SFSE! This is an excellent first question. If you haven't yet, feel free to read about How to Ask and take our quick tour. We hope you find your experience here pleasant!
    – sfdcfox
    Commented Nov 10, 2023 at 1:28

1 Answer 1

0

When you first assign the property value, then call refreshApex immediately, the wire handler hasn't had a chance to be notified of the change yet, as this happens later in the LWR life cycle, so it sees the old value. It also has some kind of "debouncing" effect to prevent infinite recursion on wire calls. The net effect is that you'd need another refreshApex later to fix this.

Instead, call refreshApex only if the value hasn't changed:

if(this.myParamProperty === newValue) {
  refreshApex(this.myWiredProperty);
} else {
  this.myParamProperty = newValue;
}
4
  • Thanks @sfdcfox, tried this but now the wire handler is not being called (not creating logs on the server). That is what I was expecting initially, not to have to call refreshApex because just updating this.myParamProperty (made reactive in the wire handler call) should re-call the server automatically, but that is not happening. Any thoughts? Commented Nov 10, 2023 at 10:31
  • @DannyMarfil I'll write up a demo today. Give me a bit.
    – sfdcfox
    Commented Nov 10, 2023 at 15:12
  • @DannyMarfil So, I built a bare-bones demonstration of this, and as I expected, the wire method is triggered correctly without refreshApex, and refreshApex was actually causing an error. So, I can't tell you what the problem is, but I can tell you this is not the problem. It's probably a typo or some kind of race condition. If it's possible, you can send me a copy of the code offline and I'd be happy to review it. Email's in my profile.
    – sfdcfox
    Commented Nov 10, 2023 at 20:29
  • Thanks a lot @sfdcfox, email sent :-) Commented Nov 13, 2023 at 12:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .