Uh oh!
There was an error while loading. Please reload this page.
fix(ios): resolve reactHost lazily so paste works under Expo bridgeless - #56
Conversation
Warning Review limit reached
Next review available in:14 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. 📝 WalkthroughWalkthroughUpdated ChangesLazy reactHost resolution
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…under Expo bridgeless The iOS paste swizzle never installed because PasteInputModule captures reactHost once in +setup:, but Expo creates the RCTHost lazily after that call, leaving reactHost nil. Patch re-reads it from the rootViewFactory at lookup time. Upstream: mattermost/react-native-paste-input#56.
a6e711c to
4d2b76bCompare4d2b76b to
7344307Compare
Problem
On v2.0.x with the New Architecture (bridgeless), iOS paste interception silently never registers when the app is hosted by Expo (
ExpoReactNativeFactory/EXReactRootViewFactory).onPastenever fires and the system "Paste" affordance falls through to the defaultUITextViewhandler — so for image-only clipboard contents the library appears to do nothing.This is distinct from #54 / #55: even with a valid native tag (registration reaches the native module), the native side can't locate the backing text view to swizzle, so the interception is never installed.
Reproduced on React Native 0.85.3 + Expo SDK 56,
RCT_NEW_ARCH_ENABLED=1(bridgeless).Root cause
PasteInputModuleresolves the Fabric surface presenter (used to look up the backingUITextViewby tag) from areactHostcaptured once in+setup::But the base
RCTRootViewFactorycreates theRCTHostlazily, insideviewWithModuleName:→createReactHostIfNeeded:— it only assignsself.reactHostwhen the first surface mounts. Under Expo that mount happens afterapplication:didFinishLaunchingWithOptions:returns, i.e. after the app'sPasteInputModule.setup(factory.rootViewFactory)call. SorootViewFactory.reactHostis stillnilwhensetupcaptures it, and because it's stored in astaticit is never refreshed.The bridge fallback in
getSurfacePresenterdoesn't help either: in bridgeless modeself.bridgeis anRCTBridgeProxywhosesurfacePresenterisnil.Net effect:
getSurfacePresenterreturnsnil→findBackingTextViewForTag:finds nothing → the register retry loop exhausts and gives up → thepaste:/canPerformAction:swizzle is never applied.Evidence
Captured with temporary
NSLogs while diagnosing.Before:
After:
Fix
Drop the
_reactHoststatic captured in+setup:and instead retain therootViewFactory, readingreactHostfresh from it ingetSurfacePresenterat view-lookup time. By then the host has been created. Reading it fresh each time (rather than caching a value that may have been nil at setup) keeps a single source of truth.Only touches
ios/PasteInputModule.mm. No behavior change on setups whererootViewFactory.reactHostis already populated atsetuptime.Testing
<PasteInput onPaste={…} />focused, PNG on the pasteboard (host → sim viaxcrun simctl pbsync host). System Paste →onPastefires with the image after this change; nothing before.canPerformAction(paste:)returnsYESfor image contents) and unregisters cleanly on unmount.Notes
__nativeTagissue (v2 paste interception silently bails on RN 0.76+ Fabric (uses__nativeTagwhich is undefined) #54 / fix(ios): use findNodeHandle to register PasteInput on Fabric #55) also applies; on RN 0.85__nativeTagis populated, so this native fix alone restores paste.