Description
To enable reactivity, the @wire
decorator transforms code in such a way that computed properties are re-computed whenever updates are needed. This means that variables used as property keys must have string representations that never change.
Example transformation
The following snippets are excerpts, not complete code.// input.js
const symbol = Symbol.for("key");
export default class Test extends LightningElement {
@wire(getFoo, {
[symbol]: "$prop1",
string: "$prop2",
notReactive: 'just hanging out'
})
wiredFoo;
}
// output.js
const symbol = Symbol.for("key");
class Test extends LightningElement {
wiredFoo;
}
_registerDecorators(Test, {
wire: {
wiredFoo: {
adapter: getFoo,
dynamic: [symbol, "string"],
config: function ($cmp) {
return {
notReactive: 'just hanging out',
[symbol]: $cmp.prop1,
string: $cmp.prop2
};
}
}
}
});
For reactivity to properly function, the object returned by the config
method must always have the keys in the dynamic
array.
In #3955, we updated the @wire
validation to only permit identifiers that were declared as a const
. This prevents accidentally changing the value and breaking reactivity. However, this is not a complete solution, as the string representation of an object may change (e.g. { toString: Math.random }
). Additionally, the solution does not permit constants that were imported from another file, even if those constants would otherwise be acceptable to use. (A simple workaround for the import problem is to declare a new constant in the component file.) We should validate that the value for a constant is not an object; only primitives should be allowed as computed property keys.
Additionally, in the same PR we allowed primitives to be used directly as property keys, as that is perfectly valid JavaScript with a static string representation. We did not permit template literals, as they contain expressions that can change (e.g. `${Math.random()}`
). We may want to do analysis of template literals, and allow them to be used if we can determine that they have a static string representation (e.g. `without expressions`
, `with ${1} static expression`
).
For example, the following is currently allowed, but should not be.
// every time the property is computed, it results in a different value
const toStringChanges = { toString: Math.random }
@wire(getFoo, { [toStringChanges]: "$prop" }) nonDeterministicObject;
And following examples are currently not allowed, but should be.
// imported constants should be treated the same as constants declared in the file
import { IMPORTED_CONSTANT } from "./config";
@wire(getFoo, { [IMPORTED_CONSTANT]: "$prop" }) importedConstant;
// the computed string will never change for these template literals
@wire(getFoo, [`no expressions`]: "$prop" }) noExpressions;
@wire(getFoo, [`${1} expression`]: "$prop" }) oneExpression;