I've come across some behavior that had me scratching my head for quite a while, and I'm trying to figure out if it's expected, and what workarounds are best suited to avoiding the issue. The basic setup is to have a Lightning Web Component
with an added .js
file we import.
Files:
- myComponent.js
- myComponent.html
- helper.js
It's a pretty useful pattern to break apart our logic into smaller, more manageable chunks. The helper structure is roughly as below:
const service = {
primitiveAttribute: true,
arrayAttribute: [],
objectAttribute: {
primitiveAttribute: false,
someFunction: function () { /*implementation*/ }
}
};
export { service as default };
And the main file looks roughly as below:
import service from "./helper";
// ...somewhere else in the file
this.service = {
...service, otherAttributes
};
Now let's say I embed this component on a record page, and open two different records in separate tabs. What's blowing my mind is that, if I change this.service.objectAttribute.primitiveAttribute
on one tab, that change is reflected on the other at well. It seemed to me like spreading in the attributes would work. I tried changing the spread to use structuredClone
, but it's not supported yet.
Making the situation more complicated is that I have some attributes (such as functions) that would not be copied using the time tested JSON.parse(JSON.stringify(...))
trick. So the only workaround I've found is to copy it over inelegantly as below.
this.service.objectAttribute = {
someFunction: this.service.objectAttribute.someFunction,
...JSON.parse(JSON.stringify(this.service.objectAttribute))
};
So now, I'm wondering:
- Is this behavior a bug or Working As Designed?
- Is it possible to move complex service structures to a separate file without sharing the reference?
- Surely, there must be a better way.
I could certainly see how this behavior could be abused to produce some interesting results.