Move mobile browser ref mirrors out of effects (#3230)

* Move mobile browser refs out of effects

* Use layout effect for mobile browser ref mirrors

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil 2026-05-29 19:27:24 -07:00 committed by GitHub
parent 6bf69c3638
commit f2f6493316
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 40 additions and 12 deletions

View File

@ -1,5 +1,13 @@
import { Buffer } from 'buffer'
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
import {
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
type ReactNode
} from 'react'
import {
ActivityIndicator,
AppState,
@ -209,21 +217,14 @@ export function MobileBrowserPane({
}
}, [addressFocused, tab.url])
useEffect(() => {
useLayoutEffect(() => {
// Why: gesture and stream handlers need committed values before passive
// Effects flush, without leaking refs from an uncommitted render.
frameMetadataRef.current = frameMetadata
}, [frameMetadata])
useEffect(() => {
layoutRef.current = layout
}, [layout])
useEffect(() => {
dialogRef.current = dialog
}, [dialog])
useEffect(() => {
zoomRef.current = zoom
}, [zoom])
}, [dialog, frameMetadata, layout, zoom])
useEffect(() => {
lastZoomResetUrlRef.current = tab.url || 'about:blank'

View File

@ -0,0 +1,27 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
const source = readFileSync(new URL('./MobileBrowserPane.tsx', import.meta.url), 'utf8')
function sliceBetween(startPattern: string, endPattern: string): string {
const start = source.indexOf(startPattern)
expect(start).toBeGreaterThanOrEqual(0)
const end = source.indexOf(endPattern, start)
expect(end).toBeGreaterThan(start)
return source.slice(start, end)
}
describe('MobileBrowserPane source invariants', () => {
it('mirrors handler refs in a layout effect instead of during render', () => {
const mirrorBlock = sliceBetween(
'useLayoutEffect(() => {',
' useEffect(() => {\n lastZoomResetUrlRef.current'
)
expect(mirrorBlock).toContain('frameMetadataRef.current = frameMetadata')
expect(mirrorBlock).toContain('layoutRef.current = layout')
expect(mirrorBlock).toContain('dialogRef.current = dialog')
expect(mirrorBlock).toContain('zoomRef.current = zoom')
expect(mirrorBlock).toContain('}, [dialog, frameMetadata, layout, zoom])')
})
})