Version
v5
Reanimated Version
v3
Gesture Handler Version
v2
Platforms
iOS, Android
What happened?
Since 5.2.11 (modal status rewrite, #2632), calling dismiss() on a BottomSheetModal that has never been presented permanently wedges the modal:
every subsequent present() mounts state but renders nothing. No error, no warning. The same call was a safe no-op on <= 5.2.10.
Root cause (from diffing 5.2.10 vs 5.2.14 source):
-
handleDismiss early-exits only for CLOSED, MINIMIZED, and DISMISSING at index -1 — MODAL_STATUS.INITIAL is NOT covered. So a dismiss on a never-presented modal falls through to:
statusRef.current = MODAL_STATUS.DISMISSING + bottomSheetRef.current?.forceClose() — but the ref is null (never mounted), so forceClose is a silent no-op and no callback ever transitions the status again. The modal is stuck in DISMISSING.
-
handlePortalRender returns early while status is DISMISSING, so every later present() sets mount: true but the portal content is never rendered.
handlePresent never resets the status (it only sets ANIMATING when the sheet was already mounted), so there is no recovery path.
Common real-world trigger: a visible-prop wrapper component whose effect runs its else-branch on first mount:
useEffect(() => {
if (visible) modalRef.current?.present();
else modalRef.current?.dismiss(); // runs once at mount,
visible=false
}, [visible]);
This pattern worked for years on <= 5.2.10.
Likely related: #2703 — same trigger (dismiss() on a never-presented modal), different symptom (spurious onDismiss vs. permanently blocked present()).
Both stem from handleDismiss not early-exiting on MODAL_STATUS.INITIAL.
Reproduction steps
- Render a BottomSheetModal ref={ref} snapPoints={[300]}...
- Call ref.current.dismiss() before ever presenting (e.g. from an effect)
- Call ref.current.present()
- Nothing appears — and no present() call ever works again for this modal
Expected behavior:
dismiss() on a never-presented modal should be a no-op (as in <= 5.2.10), and present() should always be able to present. Suggested fix: include INITIAL (and DISMISSED) in handleDismiss's early-exit list, and/or reset statusRef in handlePresent.
Reproduction sample
https://snack.expo.dev/@pvap/bottom-sheet---issue-reproduction-template
Relevant log output
No output — the failure is completely silent. No error, no warning.
present() executes normally but handlePortalRender skips rendering while the internal MODAL_STATUS is stuck in DISMISSING.
Version
v5
Reanimated Version
v3
Gesture Handler Version
v2
Platforms
iOS, Android
What happened?
Since 5.2.11 (modal status rewrite, #2632), calling
dismiss()on a BottomSheetModal that has never been presented permanently wedges the modal:every subsequent
present()mounts state but renders nothing. No error, no warning. The same call was a safe no-op on <= 5.2.10.Root cause (from diffing 5.2.10 vs 5.2.14 source):
handleDismissearly-exits only forCLOSED,MINIMIZED, andDISMISSINGat index -1 —MODAL_STATUS.INITIALis NOT covered. So a dismiss on a never-presented modal falls through to:statusRef.current = MODAL_STATUS.DISMISSING+bottomSheetRef.current?.forceClose()— but the ref is null (never mounted), so forceClose is a silent no-op and no callback ever transitions the status again. The modal is stuck in DISMISSING.handlePortalRenderreturns early while status is DISMISSING, so every laterpresent()setsmount: truebut the portal content is never rendered.handlePresentnever resets the status (it only sets ANIMATING when the sheet was already mounted), so there is no recovery path.Common real-world trigger: a
visible-prop wrapper component whose effect runs its else-branch on first mount:useEffect(() => {
if (visible) modalRef.current?.present();
else modalRef.current?.dismiss(); // runs once at mount,
visible=false
}, [visible]);
This pattern worked for years on <= 5.2.10.
Likely related: #2703 — same trigger (dismiss() on a never-presented modal), different symptom (spurious onDismiss vs. permanently blocked present()).
Both stem from handleDismiss not early-exiting on MODAL_STATUS.INITIAL.
Reproduction steps
Expected behavior:
dismiss() on a never-presented modal should be a no-op (as in <= 5.2.10), and present() should always be able to present. Suggested fix: include INITIAL (and DISMISSED) in handleDismiss's early-exit list, and/or reset statusRef in handlePresent.
Reproduction sample
https://snack.expo.dev/@pvap/bottom-sheet---issue-reproduction-template
Relevant log output