I've seen many examples with primitive data types, but I've been trying to propagate array down to my children component and encountered some problems.
My parent component looks like this:
<template>
<lightning-card title="ListReference">
<div class="slds-p-around--medium">List: {listString}</div>
<c-list-reference-inner
list={list}
></c-list-reference-inner>
</lightning-card>
</template>
and its javascript:
import {LightningElement, track, api} from 'lwc';
export default class ListReference extends LightningElement {
@track list = [{},{},{}];
constructor() {
super();
setInterval(() => {
this.list = [...this.list];
}, 3000);
}
get listString() {
return JSON.stringify(this.list);
}
}
This is how my child component listReferenceInner looks like:
<template>
<lightning-button
variant="brand"
label="mutate list"
class="slds-m-left_x-small"
title="mutate"
onclick={mutateListElement}
></lightning-button>
</template>
and javascript:
import {LightningElement, api} from 'lwc';
export default class ListReferenceInner extends LightningElement {
@api list;
mutateListElement() {
this.list.forEach(element => element.ttt = 'ttt');
}
}
What happens is that when the button on the child component is clicked, the array's elements are updated. I also put setInterval to the parent component's constructor, which just clones the array so the @track catches this change and rerender the component so we can see that the array changes were propagated up from the child component. So far I know this isn't something we want, because LWC uses one-way binding.
Moreover, if I change the decorator on the parent component from @track to @api, the child function mutateListElement
quietly dies on the first element.ttt = 'ttt'
, maybe because of some trap on the element's proxy.
I believe I could solve this with a setter on the child list which would make a copy of that array, but I find that ugly. So my question is how to treat object references when propagated like this?
Thanks for any answers!