Skip to content

Conversation

@jhefferman-sfdc
Copy link
Contributor

Details

Fixes a property observation issue in the context connection and disconnection. By accessing the component properties, they are marked for observation and in very specific scenarios (see accompanying tests) this can become an issue and cause components to re-render when they shouldn't.

Does this pull request introduce a breaking change?

  • 😮‍💨 No, it does not introduce a breaking change.

Does this pull request introduce an observable change?

  • 🤞 No, it does not introduce an observable change.

GUS work item

W-19830319

@jhefferman-sfdc jhefferman-sfdc requested a review from a team as a code owner October 13, 2025 02:43
],
});
// Legacy SSRv1 does not support context when inherited
if (!process.env.ENGINE_SERVER) {
Copy link
Contributor Author

@jhefferman-sfdc jhefferman-sfdc Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inherited context doesn't work for legacy SSR (V1), but it never did. Testing for this results in a number of hydration errors for V1 only.

Comment on lines 98 to 100
fieldsOrProps: {
[name: string]: any;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about defining a type that we can re-use for both connect/disconnect :

    type VMFieldsOrProps = VM['cmpFields'] | VM['cmpProps'];
    fieldsOrProps: VMFieldsOrProps

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, changed the function signature to to the gate. Original had to be so reverted to that.

Comment on lines +16 to +22
// 1. The template change results in the parent component being marked as dirty.
// 1a. Marking the parent as dirty sets the currentReactiveObserver to the parent, here: https://github.com/salesforce/lwc/blob/master/packages/%40lwc/engine-core/src/libs/mutation-tracker/index.ts#L83
// 2. The new template doesn't contain the child so disconnectContext is called on the child component. The BUG: If the child properties are incorrectly observed then riggering disconnectContext marks all child properties
// for observation using the currentReactiveObserver of the parent set in 1a. here: https://github.com/salesforce/lwc/blob/master/packages/%40lwc/engine-core/src/libs/mutation-tracker/index.ts#L60
// 3. Next, a delayed property mutation inside the child component's renderedCallback occurs and this delayed (post disconnection) mutation triggers valueMutated, where all the parent properties are registered listeners.
// That happens here: https://github.com/salesforce/lwc/blob/master/packages/%40lwc/engine-core/src/libs/mutation-tracker/index.ts#L41
// 3b. This causes the parent component to re-render.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jhefferman-sfdc can you check if enabling this flag will fix the issue as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not. See tests here:

Comment on lines 153 to 157

const enumerableKeys = keys(getPrototypeOf(component));
const enumerableKeys = keys(fieldsOrProps);
const contextfulKeys = ArrayFilter.call(enumerableKeys, (enumerableKey) =>
isTrustedContext((component as any)[enumerableKey])
isTrustedContext(fieldsOrProps[enumerableKey])
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change we're only including the values in cmpProps and cmpFields while previously we were looking for all of the fields in the component instance prototype chain.

@jhefferman-sfdc just want to confirm, do we only care about the fields in cmpProps and cmpFields for context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change we're only including the values in cmpProps and cmpFields while previously we were looking for all of the fields in the component instance prototype chain.

@jhefferman-sfdc just want to confirm, do we only care about the fields in cmpProps and cmpFields for context?

@jmsjtu are you referring to inherited context? We do care about this but the respective objects include it. See related test here. I checked manually too for decorated and non-decorated.

Copy link
Member

@jmsjtu jmsjtu Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posting for posterity, we discussed offline.

@jmsjtu are you referring to inherited context? We do care about this but the respective objects include it. See related test #5536 (comment). I checked manually too for decorated and non-decorated.

I actually meant going from keys(getPrototypeOf(component)); 👉 keys(fieldsOrProps); we're now only looking at the field defined in the class instead of all the properties on the prototype.

We don't think it should be an issue though as context needs to be set on the class that extends LightningElement

@jhefferman-sfdc jhefferman-sfdc enabled auto-merge (squash) October 13, 2025 21:38
@jhefferman-sfdc jhefferman-sfdc merged commit 4ca7f2a into master Oct 13, 2025
10 checks passed
@jhefferman-sfdc jhefferman-sfdc deleted the jhefferman/context-fix branch October 13, 2025 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants