Lightning Web Components – LWC Doesn’t Re-render When Already Rendered Property is Updated

I want to have a getter within a component that updates the value of another reactive property. This works when the other property is below the getter in the template, but not when it is above.

Here is a simplified version of the issue

HTML:

<template>
    <p>{high}</p>
    <p>{middle}</p>
    <p>{low}</p>
</template>

Javascript:

export default class myComponent extends LightningElement {
  high;
  low;
  
  get middle(){
    this.high = 'High';
    this.low = 'Low';
    
    return "Middle";
  }
}

This is what gets displayed

                 Middle
                 Low

My guess of what is happening is that the template is rendered top to bottom, and high is undefined at the time it is rendered, because the middle getter has not been called yet. I am wondering if this is a bug in LWC? Per the documentation:

Fields are reactive. If a field’s value changes, and the field is used
in a template or in a getter of a property that’s used in a template,
the component rerenders and displays the new value.

For now I can workaround this problem using a hidden call to the getter at the top of the template.

<template>
    <div hidden>{middle}</div>
    <p>{high}</p>
    <p>{middle}</p>
    <p>{low}</p>
</template>

But this feels hacky, and in my actual example, the getter has code that I don't want to execute twice. Does anyone know of a more elegant workaround, perhaps using HTML manipulation?

Best Answer

The main problem is that the result from a getter must be idempotent. This means that it should always return the same value within the same life cycle event. Without this assumption, it'd be possible to create infinite getter loops, etc.

As such, the return value must not be modified, and this includes doing something in one getter that would affect the output of another getter, since the order of execution for getters is not deterministic. Even your workaround might not work in a future release of LWC, based on compiler optimizations, or even based on surrounding components.

This behavior isn't limited to just LWC, either. This problem can appear in Visualforce as well. It's also considered a problem in almost all frameworks (or were at some point). Doing this in a React app, for example, would likely result in a similar problem.

In short, you should only modify values during an event handler, callback, or setter method. Attempting this in a getter method, in virtually any language, is a bad idea, and if you're using that elsewhere, you should get out of the habit of doing so.

Related Topic