fix(mobile): keep split session hooks render-pure

Documents the pre-existing render-time refs the split relocated onto changed
lines, and drops a ref assignment the split added that the monolith never had.
This commit is contained in:
Neil
2026-08-31 22:14:35 -07:00
parent 0f184fac2c
commit 9ea5f0488d
5 changed files with 7 additions and 1 deletions
@@ -46,6 +46,7 @@ export function useMobileSessionAccessorySelection(scope: MobileSessionTerminalI
const repeatIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
// Why: ref keeps repeat firing the current callback; else a mid-hold tab switch/reconnect routes bytes to a stale terminal.
const handleAccessoryKeyRef = useRef(handleAccessoryKey)
// react-doctor-disable-next-line react-doctor/no-ref-current-in-render
handleAccessoryKeyRef.current = handleAccessoryKey
const stopAccessoryRepeat = useCallback(() => {
if (repeatTimeoutRef.current) {
@@ -35,6 +35,7 @@ export function useMobileSessionFeedbackCapabilities(scope: MobileSessionTermina
// Why: stable callbacks (handleFileTap) read the live value via this ref, since
// the capability probe resolves after the callbacks are created.
const browserScreencastSupportedRef = useRef(browserScreencastSupported)
// react-doctor-disable-next-line react-doctor/no-ref-current-in-render
browserScreencastSupportedRef.current = browserScreencastSupported
// Why: terminal gesture/input callbacks are stable/imperative, so keep their refs current before commit, not in a later effect.
clientRef.current = client
@@ -49,6 +50,7 @@ export function useMobileSessionFeedbackCapabilities(scope: MobileSessionTermina
)
// Why: Expo can reuse this screen for a new route; reconcile before paint so a dismissed old warning doesn't flash.
if (reconciledCreateWarningState !== createWarningState) {
// react-doctor-disable-next-line react-doctor/no-prop-callback-in-render
setCreateWarningState(reconciledCreateWarningState)
}
const createWarning = reconciledCreateWarningState.visible
@@ -95,6 +95,8 @@ export function useMobileSessionStartup(scope: MobileSessionKeyboardStateModel)
worktreeId
])
// Every setTimeout goes through addTimer into `timers`, which the returned cleanup clears.
// react-doctor-disable-next-line react-doctor/effect-needs-cleanup
useEffect(() => {
if (connState !== 'connected') {
return
@@ -76,7 +76,6 @@ export function useMobileSessionTerminalRuntime(scope: MobileSessionScreenStateM
const activeHandleRef = useRef<string | null>(null)
const bufferedTerminalDraftState = useBufferedTerminalDrafts({ activeHandle, activeHandleRef })
const reconcileBufferedDraftsRef = useRef(bufferedTerminalDraftState.reconcileTerminalTabs)
reconcileBufferedDraftsRef.current = bufferedTerminalDraftState.reconcileTerminalTabs
const activeSessionTabTypeRef = useRef<MobileSessionTabType | null>(null)
const pendingActiveSessionTabIdRef = useRef<string | null>(null)
const pendingActiveTerminalHandleRef = useRef<string | null>(null)
@@ -61,6 +61,8 @@ export function useMobileSessionTerminalSubscriptionFoundation(
[clearNativeChatInputLease, nativeChatInputLeaseReadyRef, showNativeChatRef]
)
const unsubscribeTerminalRef = useRef(unsubscribeTerminal)
// PTY event callbacks fire before passive effects flush, so they need the current unsubscribe.
// react-doctor-disable-next-line react-doctor/no-ref-current-in-render
unsubscribeTerminalRef.current = unsubscribeTerminal
const clearTerminalCache = useCallback(() => {