fix(framework): await pending language change in connectedCallback instead of skipping first render#13798
Merged
Merged
Conversation
|
🚀 Deployed on https://pr-13798--ui5-webcomponents-preview.netlify.app |
…st render PR #13602 made connectedCallback bail out early for language-aware components mounted while a language change was in progress. That path silently skipped onEnterDOM, _fullyConnected, and _domRefReadyPromise resolution — so consumers that register listeners or observers in onEnterDOM (e.g. the Udex Footer's ResizeHandler.register call) never saw those side effects wired up. Replace the boolean pending flag with a promise handle so connectedCallback can await it directly and then continue on the normal render path. This keeps the lifecycle invariant intact (onEnterDOM fires exactly once, after the first render) and removes the need for any deferred-lifecycle bookkeeping. Language.ts: - languageChangePending changes from boolean to Promise<void> | null. - A single startLanguageChange helper builds the promise, runs the deferred reRenderAllUI5Elements, and clears the field when done (only if a newer change hasn't replaced it). - setLanguage() and the cross-runtime attachConfigChange handler share the helper, so both paths keep the field consistent. - getLanguageChangePending() now returns the in-flight promise or null. UI5Element.ts: - connectedCallback awaits the pending promise for language-aware components, then proceeds normally. If the deferred re-render already rendered the element during the await, skip the redundant renderImmediately. - _invalidate keeps its existing guard - a non-null promise is truthy, so the boolean check still works semantically. Tests: - New LanguageAwareLifecycle test element (languageAware: true, counts hook calls). - New base/cypress/specs/LanguageAwareLifecycle.cy.tsx covering: * onEnterDOM fires exactly once after a pending language change resolves * onEnterDOM does not fire a second time on a subsequent re-render * onEnterDOM does not fire if the element is removed before rendering Verified locally: - 3/3 pass with the fix, 2/3 fail without it. - Existing DatePicker_cldr_race and i18n_texts specs still pass.
841f417 to
163bf61
Compare
nnaydenow
approved these changes
Jul 8, 2026
|
🧹 Preview deployment cleaned up: https://pr-13798--ui5-webcomponents.netlify.app |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #13602. That PR made
connectedCallbackbail out early for language-aware components mounted while a language change was in progress. The early-return path silently skippedonEnterDOM(),_fullyConnected = true, and the_domRefReadyPromiseresolution — so consumers that register listeners or observers inonEnterDOMnever saw those side effects wired up.Reporter symptom
Reported against
udex-footer(built on top of UI5 Web Components):setLanguage("zh_CN")without awaiting → language change pending.<udex-footer>inserted while pending →connectedCallbackhits the early return atUI5Element.ts:362.ResizeHandler.registernever runs → mobile Accordion never appears because the resize observer never fires.Fix
Instead of bailing out (which desynchronized the lifecycle), await the pending language change and then continue on the normal render path. To make that ergonomic,
languageChangePendinginLanguage.tsis repurposed from a boolean flag into a promise handle — the in-flight settlement promise, ornullwhen no change is pending.Language.tslanguageChangePending: Promise<void> | nullreplaces the boolean.startLanguageChangehelper builds the promise (chainingfireLanguageChange+ the deferredreRenderAllUI5Elements) and clears the field on.finally— only if a newer change hasn't already replaced it.setLanguage()and the cross-runtimeattachConfigChangehandler share the helper, so both paths keep the field consistent.getLanguageChangePending()now returns the in-flight promise ornull.UI5Element.ts—connectedCallbackA small guard skips the redundant
renderImmediately(this)if the deferredreRenderAllUI5Elementsalready rendered the element during the await.UI5Element.ts—_invalidateUnchanged.
getLanguageChangePending()in a truthy context still means "a change is in flight, don't invalidate now".Why this shape
onEnterDOMfires exactly once, after the first render, on the natural code path — no deferred bookkeeping.Language.ts— either a promise ornull— captures pending-ness. No boolean/promise pair to keep in sync.await getLanguageChangePending()without adding another synchronization surface.Tests
packages/base/test/test-elements/LanguageAwareLifecycle.tsx—languageAware: true, counts each lifecycle hook invocation.packages/base/cypress/specs/LanguageAwareLifecycle.cy.tsx:onEnterDOMfires exactly once after a pending language change resolvesonEnterDOMdoes not fire a second time on a subsequent re-renderonEnterDOMdoes not fire if the element is removed before renderingVerified locally:
main/cypress/specs/DatePicker_cldr_race.cy.tsx(from fix(framework): prevent language-aware components from rendering before CLDR data loads #13602): still passes.base/cypress/specs/i18n_texts.cy.tsx: still passes.yarn lintclean.Backport
Should be cherry-picked to the 2.23.x line since #13602 shipped there and Udex is affected.
Related
sapudex/digital-design-systemFooter component.