Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

array mutations are not reactive in a custom lightning-datatable component. #4341

Open
vignesh191 opened this issue Jul 1, 2024 · 2 comments
Labels

Comments

@vignesh191
Copy link

Description

When using a custom type lightning-datatable, methods such as push, pop, and splice on the data array are not reactive and do not cause a re-render on the custom type datatable element.

Steps to Reproduce

An example of a custom type lightning-datatable is described in these developer docs

As described in the above linked docs, a custom type datatable consists of the following layers:

  • wrapper element (columns and data are defined here)
    • custom-type-datatable element (extends LightningDatatable and declares static customTypes)

When doing an array mutation method on the data in the wrapper layer, the data attribute is not reactive, even when using @track.

LWC version: 6.5.3

@vignesh191 vignesh191 changed the title array mutations with push, pop, or splice are not reactive in a custom lightning-datatable component. array mutations are not reactive in a custom lightning-datatable component. Jul 1, 2024
@nolanlawson
Copy link
Collaborator

Thanks for filing! Do you have a repro you can share, e.g. using https://playground.lwc.dev?

I tried to write a minimal repro, but my repro seems to be working as documented. If I use @track and @api, then I can use push/pop/splice and the rendered output is updated.

@nolanlawson nolanlawson added the bug label Jul 1, 2024
@nolanlawson
Copy link
Collaborator

nolanlawson commented Jul 10, 2024

I worked with @roxanne-baker and we found a minimal repro. The key issue is:

The parent passes in a data to its child:

<x-child data={data}></x-child>

The parent makes data deep-reactive using @track:

@track data = []

The parent tries to update data to update the child:

this.data.push(count++)

However, the child doesn't update! The reason is that the child is using a setter to copy the data to another property, state.data:

    @track state = { data: [] }

    @api set data(data) {
      this.state.data = [...data]
    }
  <template for:each={state.data} for:item="datum">
      <div key={datum}>{datum}</div>
  </template>

If the child were to avoid cloning the data instead:

 this.state.data = [...data]
+this.state.data = data

... then the reactivity works!

This is actually longstanding LWC behavior, and goes back to at least LWC v3.0.0.

The reason the child doesn't update is that the parent is passing in the reference to the data, which causes the set data on the child to get called. But if the data has not changed (by reference), then the set data on the child is never called.

It works if you don't clone the data due to a quirk – the data is @tracked by the parent, so when the child template function executes, the entire data array is made reactive w.r.t. the child template. So the child template will re-run anytime anything in the data changes, which means that we don't care if the set data is called again (it's not), because the state.data is the exact same object as the data anyway.

This is maybe not a bug in LWC, but it is certainly counter-intuitive behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants