Wednesday, 29 March 2023

Lightning Web Component References in Spring '23

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

So why should we use references, when we can already provide a reference via a data attribute, and dynamically generate the value to boot? There are a few good reasons:
  •  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. 

Related Posts




No comments:

Post a Comment