Tweet |
Introduction
Another week, another post about new LWC directives in 'Spring 23 - this time the lwc:ref directive. As the name suggests, this provides a reference to the component, one that can be used in JavaScript to access the element with a minimum of fuss.
Usage
To define a reference to a component, simply specify the lwc:ref directive in the HTML:
<h1 class="slds-var-m-bottom_small" lwc:ref="Heading1">Directives</h1>
and to access the element in JavaScript via the reference:
const headingEle=this.refs.Heading1;
As this.refs is an object, you can also retrieve a reference based on a variable:
const refVal='Heading1'; ... const chosenEle=this.refs[refval];
Notes/Gotchas
The reference value in the HTML markup must be a string literal - you can't use properties to dynamically generate the reference. This has the knock-on effect that you can't use it in loops to generate a unique reference for each element. If you try, you'll get an error similar to the following when you deploy or push your source:LWC1158: Invalid lwc:ref usage on element "<li>". lwc:ref cannot be used inside for:each or an iterator.
Hopefully this will change in a future release, as it's a key use case that has been a struggle since Visualforce days.
You can, however, define multiple references with the same name - in this case the last one defined will win. I'm surprised that this isn't blocked by the platform, as it feels like a really easy mistake to make and one that I'm sure I'll encounter a lot over the next couple of years!
If you extract a reference that doesn't exist, in true JavaScript fashion it will return null rather than indicating an error. Always check your reference resolved to an element before taking any further action!
Why Use Refs
-
Clarity. A data attribute is a generic mechanism for storing
additional information on an HTML element - information that is useful to
the application. In order to determine the purpose of this information, I
need to examine the JavaScript to figure out how it is used. A reference,
on the other hand, has a single purpose - to provide a way to locate the
element based on the reference value - no need to look at any JavaScript. As mentioned above, I have to compromise on this clarity and fall back on
data attributes to dynamically generate a value, but hopefully that will
be coming soon.
-
Cleanliness. Data attributes appear in the rendered HTML, while references
don't. This also has the benefit that you aren't exposing something you
rely on to possible external interference or for someone else's code to rely on, thus creating an unexpected dependency.
- Performance - my opinion! I'd also imagine that it's more performant to use references than executing selector queries - the this.refs object is built once, applies to the current template only, and I then extract elements anywhere in my JavaScript with no additional effort. Using selectors I have to execute a query each time I need an element, and I might need multiple selectors to find disparate elements by their attributes. This is the case in Vue.js which has it's own references implementation, so I'd imagine LWC is similar.