fix(android): initial measuring tweaks - #784
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes an Android-only race in initial height estimation for EnrichedTextInputView when defaultValue is set and fontSize is missing/invalid, by preventing MeasurementStore from caching “fresh” sizes until the shadow node can actually be invalidated.
Changes:
- Default
fontSizeused duringinitialMeasurenow falls back to the view’s default whenfontSizeisnullor<= 0. MeasurementStore.storenow invalidates the shadow node via a callback and only commits the new cached size when invalidation succeeds.- Initializes
forceHeightRecalculationCounter_in the shadow node and aligns the counter value sent via state updates.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.h | Initializes forceHeightRecalculationCounter_ to avoid undefined comparisons. |
| android/src/main/java/com/swmansion/enriched/textinput/MeasurementStore.kt | Avoids caching new measured sizes unless shadow-node invalidation succeeds; improves fontSize fallback in initialMeasure. |
| android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewLayoutManager.kt | Passes an invalidation callback into MeasurementStore.store and updates the state counter post-increment. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Could you provide human readable description? I've tried reading that, but completely lost the plot after 3rd sentence |
Tried rewriting that. Previously, maybe I tried to put too much technical details there |
Summary
This fixes a bug where the component's initial height calculation would break if
defaultValuewas provided without an explicitfontSizeinhtmlStyleprop. The root cause was a mix of a bad initial estimate and invalid measurements caching:During
initialMeasure, missing a passedfontSizein props, meant it defaulted to 0, which caused the entire height estimate to be wrong. I fixed this by adding a fallback to the default font size, matching howEnrichedTextmeasurements already handle it.After
initialMeasure,setValue(caused by the presentdefaultValueprop) is run, which tries to update the shadow node state, butstateWrapperis stillnull. This caused theMeasurementStoreinternal cache to be out of sync with the actual shadow node's state. Fixed this by providing an early return ininvalidateLayout()- we don't callMeasurement.store()at all, ifstateWrapperis unavailable.I've also tweaked two small things: in
EnrichedTextInputShadowNode.cpptheforceHeightRecalculationCounter_was never initialized before accessing its value, which would make it have random, garbage values. I've also adjusted the providedforceHeightRecalculationCounterto thestateWrapper, as its value was always pre-increment duringinvalidateLayout(). I believe it's better to have the shadow node's and component's counters' values consistent.Sometimes the
setValue's layout invalidation could run before theinitialMeasure. That made theMeasurementStorecached measurements correct from the start, as aftersetValueruns, the actual component's size is measured, not estimated like it's the case withinitialMeasure. You can see this race condition in the attached video.Test Plan
I've provided a modified example app, so you can see the bug yourself - you can run
and then you can check out how it works after the fix
Screenshots / Videos
The race condition in action (stumbled across in a different app):
Screen.Recording.2026-08-27.at.12.12.20.mov
Compatibility
Checklist