[4.3.0 regression] `FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS` drops the remeasure of a React commit clearing a multiline TextInput (RN 0.83, Fabric)
Description
Since upgrading reanimated 4.2.1 → 4.3.4, our chat composer's controlled multiline TextInput fails to shrink after its text is cleared, whenever the cleared text contained typed newlines. The input keeps its expanded measured height while showing the placeholder. Any later layout-dirtying commit on the input (we used a 0.01pt padding toggle) instantly restores the correct height — the shadow node is never wedged; one remeasure is dropped.
We bisected this to a single static feature flag default flipped in 4.3.0 (#8716):
| Build (reanimated 4.3.4, RN 0.83.6) | Result |
|---|---|
| default flags | reproduces |
USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS: false only |
still reproduces |
| all three 4.3.0-flipped flags at 4.2.1 values | fixed |
FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS: false only |
fixed |
Also verified:
- Reproduces identically on reanimated 4.5.5 + worklets 0.11.4 with default flags; fixed by the same single flag override.
Failure signature (instrumented):
- Growth works:
onContentSizeChangefires per typed\n(native state-update path). - On the clearing React commit (
value→""): noonContentSizeChange, noonLayout, andmeasure()reports the stale height ≥2.5s later. - Wrap-only text (no typed newlines) clears/shrinks correctly — only the typed-newline growth path's shrink direction is affected.
What we ruled out (all tested in the reproducing app):
- Not a specific animated component. We removed, one class at a time, every
useAnimatedStylemount in the composer subtree (send button, attachment buttons/selector), the keyboard-controller animated wrappers (ancestors of the input), the mentions library (plain nested<Text>child still reproduces), and screen chrome — the bug survived every subtraction. It also reproduces on our simplest screen (a DM chat). - Not the settled-sync render. We instrumented
PropsRegistryGarbageCollector.syncPropsBackToReact: no sync fires temporally near failing clears. - Not retained settled entries (as visible to JS): calling
getSettledUpdates()immediately before the send returns an empty set — the clear commit still loses its remeasure.
Given the flag is compile-time (constexpr), the evidence points at the commit-path/registry code it gates rather than any specific registered node.
Steps to reproduce
In our production chat app (we could not distill this into a minimal project — see below):
- Focus the chat composer (controlled multiline TextInput, text rendered as nested
Textchildren). - Type a multi-line message using the return key at least twice (typed newlines matter — they grow the input through native state updates, and it is that path's shrink direction that breaks).
- Send: the message list gains a row and the input's value is cleared in the same React commit batch.
- The input keeps its expanded height while showing the placeholder. Any later layout-dirtying commit on the input (e.g. a 0.01pt padding change) instantly restores the correct 1-line height.
With FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS: false (its pre-4.3.0 default) the input collapses correctly every time; no other change.
Snack or a link to a repository
We were unable to create a minimal reproduction.
Reanimated version
4.3.4 and 4.5.5 (both reproduce)
Worklets version
0.8.3 (with reanimated 4.3.4) and 0.11.4 (with 4.5.5)
React Native version
0.83.6
Platforms
iOS
JavaScript runtime
Hermes (classic 0.14.1, not Hermes V1)
Workflow
Expo Dev Client (Expo SDK 55)
Architecture
New Architecture (Fabric renderer)
Reanimated feature flags
None (defaults) — setting FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS: false fixes the issue
React Native release level
None
Build type
Debug and Release (both reproduce)
Device
Real device and simulator
Device model
No response
Host machine
macOS
Acknowledgements
Yes
Source: software-mansion/react-native-reanimated