event listener does not update when the variable used in template with onevent is updated
Description
when a field is used in template as event handler and later assigned a new value , old value is still used to handle the event.
Steps to Reproduce
https://stackblitz.com/edit/salesforce-lwc-davchu?file=src%2Fmodules%2Fx%2Fcounter%2Fcounter.js
<template>
<button onclick={mainHandler}>mainHandler</button>
<button onclick={handlerChanger}>handlerChanger</button>
</template>
import { LightningElement } from 'lwc';
export default class extends LightningElement {
mainHandler = () => {window.alert('initial');};
handlerChanger = () => {
this.mainHandler = () => {window.alert('changed');};
window.alert(this.mainHandler);
}
}
Expected Results
New value of mainHandler must be called
Actual Results
Old value of mainHandler is called
Browsers Affected
tested in Chrome : Version 131.0.6778.87 (Official Build) (arm64), probably in all
Version
- LWC: 8.11.0
Possible Solution
Additional context/Screenshots Add any other context about the problem here. If applicable, add screenshots to help explain.
This is a limitation of the current LWC template compiler. One workaround is that you can use an object with a property rather than a plain function:
<template>
<button onclick={handler.onClick}></button>
</template>
export default class extends LightningElement {
handler = {
onClick: () => { console.log('foo') }
}
connectedCallback() {
this.handler.onClick = () => { console.log('bar') } // this will be used
}
}
BTW the current behavior has some performance benefits, namely that we can bind/cache the event listener once rather than re-evaluating it. So fixing this may incur a performance cost.
One workaround is that you can use an object with a property rather than a plain function:
<template> <button onclick={handler.onClick}></button> </template>export default class extends LightningElement { handler = { onClick: () => { console.log('foo') } } connectedCallback() { this.handler.onClick = () => { console.log('bar') } // this will be used } }
The example provided here works because the connectedCallback executes before the first render. The original issue mentioned is reproducible even with such objects, if the update is after the first render.