lwc icon indicating copy to clipboard operation
lwc copied to clipboard

if-elseif-else used inside an iteration doesn't benefit from keys

Open jye-sf opened this issue 2 years ago • 0 comments

Description

When we use the if-elseif-else directives as a direct child of an iteration, we're unable to benefit from any optimization using the keys due to how the nodes are generated.

If we use the directives as part of a template, the top level nodes in the list use the key of the if-elseif-else fragments, rather than the key of the actual content. It's not possible for the user to provide a key for a template node, so there's no way around this.

If we use the directives inline in an element or component, the user can provide a key for the node, but the top level nodes in the list are still the if-elseif-else fragments and their keys. The keys provided by the user are attached to the element or custom element nodes, which are children of the conditional directive nodes.

Example

Right now,

<template for:each={items} for:item="item">
    <div lwc:if={item.visible} key={item.key}>{item.value}</div>
</template>

gets compiled as something like

return api_iterator($cmp.items, function (item) {
    return item.visible
      ? api_fragment(
          0,
          [
            api_element(
              "div",
              {
                key: api_key(1, item.key),
              },
              [item.value]
            ),
          ],
          0
        )
      : null;
  });

The user-provided key is not available for the diffing algo when patching the list.

Expected Results

We should look into how we might optimize the use of if-elseif-else as the top level child in an iteration.

Constant Conditional in Iteration

If a constant or some condition unrelated to the values being iterated through is used, this is an issue with best practices:

<template for:each={items} for:item="item">
    <template lwc:if={visible}>
        <div key={item.key}>Conditional Iteration</div>
    </template>
</template>

can and probably should be written as:

<template lwc:if={visible}>
    <template for:each={items} for:item="item">
        <div key={item.key}>Conditional Iteration</div>
    </template>
</template>

No different from general programming:

for(let i=0; i<items.length; i++) {
    if(visible) { ... };
}

versus

if (visible) {
    for(let i=0; i<items.length; i++) {
        ...
    }
}

Actual Results

Browsers Affected

Version

  • LWC: x.x.x

Possible Solution

Additional context/Screenshots See https://github.com/salesforce/lwc/pull/3030#discussion_r983880586 for more details on the context

jye-sf avatar Oct 05 '22 17:10 jye-sf