[SalesForce] Array.push() on a @tracked array doesn’t cause component refresh in lightning-accordion in LWC

This may be a duplicate of Array.push() won't update Lightning Web Component View
However, that is for an @wire case, while this is for lightning-accordion.

I am attempting to use the lightning-accordion with multiple sections open.
However, the active-section-name array, when changed, is not triggering a component refresh.
This is very easy to reproduce in the Playground.
Here is the code which was lifted from the multiple.js/multiple.html example in the Component Reference: lightning-accordion
Note my only changes were to add a lightning-button and the handleClick method for that button.

It seems like the component is completely ignoring any changes to the @tracked activeSections Array. Both array methods .push() and .unshift() were equally ineffective.

Note that I was able to workaround this issue by using JSON.stringify() and JSON.parse() as shown below:

WORKAROUND:

this.activeSections.push('B');
this.activeSections = JSON.parse(JSON.stringify(this.activeSections));

Here's the Javascript:

import { LightningElement, track } from 'lwc';

export default class LightningExampleAccordionMultiple extends LightningElement {
    @track activeSections = ['A', 'C'];
    @track activeSectionsMessage = '';

    // This should open B in addition to A and C
    handleClick(event) {
        this.activeSections.push('B');       
    }

    handleSectionToggle(event) {
        const openSections = event.detail.openSections;

        if (openSections.length === 0) {
            this.activeSectionsMessage = 'All sections are closed';
        } else {
            this.activeSectionsMessage =
                'Open sections: ' + openSections.join(', ');
        }
    }
}

Here's the HTML template:

<template>
    <p>{activeSectionsMessage}</p>
    <lightning-button label="Open-B" title="Open B" onclick={handleClick} class="slds-m-left_x-small"></lightning-button>

    <lightning-accordion allow-multiple-sections-open
                         onsectiontoggle={handleSectionToggle}
                         active-section-name={activeSections}>
        <lightning-accordion-section name="A" label="Accordion Title A">
            <p>This is the content area for section A.</p>
            <p>Donec vitae tellus egestas, faucibus ipsum ac, imperdiet erat. Nam venenatis non ante at sagittis. Integer vel purus eget nunc semper placerat. Nam tristique quam leo, et posuere enim condimentum quis. Ut sagittis libero id lectus tempor maximus. Nunc ut tincidunt eros, a hendrerit leo. Suspendisse quis fermentum dolor. Nulla euismod consectetur leo, id condimentum nunc consequat quis.</p>
        </lightning-accordion-section>

        <lightning-accordion-section name="B" label="Accordion Title B">
            <p>This is the content area for section B.</p>
            <p>Nam at elit et justo scelerisque ullamcorper vel a felis. Mauris sit amet lorem sed est sagittis blandit nec ac turpis. Ut a mi id turpis pharetra ornare. Nullam rhoncus feugiat nunc, ac pulvinar felis pulvinar at. Nullam efficitur aliquet justo et ultricies. Maecenas eu felis aliquam, tincidunt elit at, suscipit leo. Duis ut urna nec nibh hendrerit lacinia. Sed non auctor libero. Sed pellentesque tempor mollis.</p>
        </lightning-accordion-section>

        <lightning-accordion-section name="C" label="Accordion Title C">
            <p>This is the content area for section C.</p>
            <p>Nulla ornare ipsum felis, vel aliquet dui blandit vel. Integer accumsan velit quis mauris pharetra, nec sollicitudin dui eleifend. Cras condimentum odio mi, nec ullamcorper arcu ullamcorper sed. Proin massa arcu, rutrum a ullamcorper nec, hendrerit in sem. Etiam tempus eros ut lorem tincidunt, id condimentum nulla molestie. Morbi hendrerit elit pretium, ultrices neque non, ullamcorper justo. Quisque vel nisi eget eros efficitur semper. Nulla pulvinar venenatis quam vitae efficitur. Nam facilisis sollicitudin quam ac imperdiet.</p>
        </lightning-accordion-section>
    </lightning-accordion>
</template>

Best Answer

If we create a new array as below, @track sees the change:

this.myArray = [...this.myArray, myNewElement];

My guess is that the @track isn't noticing the original push in the array since an array is actually only a pointer. When items are added to an array, it will never change the pointer, thus @track sees no change. (@track is only watching the address)

However, in my workaround above, a brand new array is created which will change the pointer. @track sees the new pointer and refreshes accordingly.

I would say this behavior is not a bug with @track, but needs to be understood by LWC developers.

Related Topic