PATTERN Cited by 1 source
Native-side lifecycle for hybrid component¶
Pattern¶
When a React Native component whose native peer is manipulated by a separate native module (the classic example: a WebView that a Mobile Bridge native module swaps out to intercept navigation) breaks under the new architecture's synchronous rendering — remove the React Native ownership entirely and let the native side manage the component's full lifecycle. Expose a thin RN placeholder that the native side can attach to; keep the heavyweight logic (WebView, camera, map, video player, etc.) in native code.
The canonical wiki instance is Shopify's 2025 migration fix for Mobile Bridge's TransportableView (see sources/2025-09-12-shopify-migrating-to-react-natives-new-architecture).
Forces¶
- Hybrid components are common — WebViews that need native navigation interception, map views, camera views, rich-text editors, etc.
- The RN-native swap pattern — where a native module replaces or reparents views declared in React Native code — works sometimes in the old architecture because view-hierarchy consistency is enforced loosely.
- The new architecture enforces hierarchy strictly. When a native module swaps a view that the RN shadow tree still thinks is in place, RN and the native OS disagree about the view hierarchy. Observable symptoms: tap gestures don't fire (the tap hits a view the RN layer thinks exists but isn't present), or the component crashes outright.
- A full React Native rewrite of the hybrid behavior may be out of scope for the migration window.
Solution shape¶
Three options in order of preference:
Option 1 — Move to pure React Native¶
If the hybrid exists because of historical reasons and a pure- RN solution is feasible, convert it. Simplest long-term outcome; highest engineering cost.
Option 2 — Move the hybrid component entirely to native¶
The option Shopify chose for the Mobile Bridge WebView case: "We solved this problem by completely removing the WebView from React Native and managing its lifecycle entirely on the native side. This was the simplest approach for our situation since we wanted to maintain compatibility with both architectures and reuse as much of our existing implementation as possible."
Mechanism:
- The WebView (or analogous hybrid) is created, mounted, resized, unmounted, and destroyed by native code — never referenced in the RN component tree.
- RN renders a placeholder (native component) that the native side can position itself relative to, or the native side positions the WebView directly at screen coordinates determined outside RN.
- Communication between RN and the WebView goes through a native module (events up, commands down) — not through RN shadow-tree manipulation.
Option 3 — Rewrite using custom shadow nodes¶
Implement the hybrid as a first-class new-architecture component with custom shadow nodes. Highest fidelity but highest engineering cost. Shopify referenced the Software Mansion blog post on custom shadow nodes as prior art.
Why option 2 is often the right answer¶
Option 2 minimises new engineering while maximising architecture-independence:
- The RN-side surface area shrinks to a placeholder, so the component is trivially compatible with both architectures.
- The native code path is unchanged (same Swift/Kotlin code that already works in production).
- The bug class — view-hierarchy desync from shadow-tree manipulation — is eliminated by removing the manipulation.
The cost: the feature is no longer "a React Native component"; it's a native feature with an RN placeholder. Teams that prefer everything on the JS side will find this architecturally unappealing; teams optimising for migration velocity find it pragmatic.
Related¶
- systems/react-native — framework context.
- concepts/view-flattening — a related mechanism by which the new architecture's stricter tree management exposes latent assumptions.
- concepts/state-batching — same pattern: new-architecture strictness exposes latent assumptions in consumer code.
- companies/shopify — origin of the canonical instance (Mobile Bridge TransportableView).