Unblock React Compiler for 6 components by removing render-phase ref access (#11544)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tomasz Zawadzki
2026-08-27 17:10:10 +02:00
committed by GitHub
parent b9bff931a3
commit f298a4ef5e
6 changed files with 27 additions and 41 deletions
@@ -270,10 +270,6 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
// Track seen profiles // Track seen profiles
const seenProfilesRef = useRef<Set<string>>(new Set()) const seenProfilesRef = useRef<Set<string>>(new Set())
const itemsRef = useRef(items)
itemsRef.current = items
const selectedInterestRef = useRef(selectedInterest)
selectedInterestRef.current = selectedInterest
const onViewableItemsChanged = useNonReactiveCallback( const onViewableItemsChanged = useNonReactiveCallback(
({viewableItems}: {viewableItems: ViewToken[]}) => { ({viewableItems}: {viewableItems: ViewToken[]}) => {
@@ -282,7 +278,7 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
if (item.type === 'profile') { if (item.type === 'profile') {
if (!seenProfilesRef.current.has(item.profile.did)) { if (!seenProfilesRef.current.has(item.profile.did)) {
seenProfilesRef.current.add(item.profile.did) seenProfilesRef.current.add(item.profile.did)
const position = itemsRef.current.findIndex( const position = items.findIndex(
i => i.type === 'profile' && i.profile.did === item.profile.did, i => i.type === 'profile' && i.profile.did === item.profile.did,
) )
ax.metric('suggestedUser:seen', { ax.metric('suggestedUser:seen', {
@@ -292,9 +288,7 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
position: position !== -1 ? position : 0, position: position !== -1 ? position : 0,
suggestedDid: item.profile.did, suggestedDid: item.profile.did,
category: category:
selectedInterestRef.current === FOR_YOU_TAB selectedInterest === FOR_YOU_TAB ? null : selectedInterest,
? null
: selectedInterestRef.current,
}) })
} }
} }
+5 -16
View File
@@ -1,11 +1,5 @@
import {Fragment, useMemo, useRef} from 'react' import {Fragment, useMemo, useRef} from 'react'
import { import {Keyboard, type StyleProp, View, type ViewStyle} from 'react-native'
Keyboard,
Platform,
type StyleProp,
View,
type ViewStyle,
} from 'react-native'
import {AtUri} from '@atproto/syntax' import {AtUri} from '@atproto/syntax'
import {msg} from '@lingui/core/macro' import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
@@ -32,7 +26,7 @@ import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Gr
import {InlineLinkText} from '#/components/Link' import {InlineLinkText} from '#/components/Link'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics' import {useAnalytics} from '#/analytics'
import {IS_NATIVE} from '#/env' import {IS_NATIVE, IS_WEB} from '#/env'
import {app} from '#/lexicons' import {app} from '#/lexicons'
import * as bsky from '#/types/bsky' import * as bsky from '#/types/bsky'
@@ -110,14 +104,9 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
} }
onPress={onPressOpen} onPress={onPressOpen}
{...(isThreadAuthor {...(isThreadAuthor
? Platform.select({ ? IS_WEB
web: { ? {onHoverIn: prefetch}
onHoverIn: prefetch, : {onPressIn: prefetch}
},
native: {
onPressIn: prefetch,
},
})
: {})} : {})}
hitSlop={HITSLOP_10}> hitSlop={HITSLOP_10}>
{({hovered, focused, pressed}) => ( {({hovered, focused, pressed}) => (
@@ -9,7 +9,7 @@ import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {mergeRefs} from '#/lib/merge-refs' import {mergeRefs} from '#/lib/merge-refs'
import {atoms as a, ios, platform, useTheme} from '#/alf' import {atoms as a, platform, useTheme} from '#/alf'
import {useInteractionState} from '#/components/hooks/useInteractionState' import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {IS_ANDROID, IS_IOS} from '#/env' import {IS_ANDROID, IS_IOS} from '#/env'
@@ -94,7 +94,11 @@ export function OTPInput({
</View> </View>
<TextInput <TextInput
// SMS autofill is borked on iOS if you open the keyboard immediately -sfn // SMS autofill is borked on iOS if you open the keyboard immediately -sfn
onLayout={ios(() => setTimeout(() => innerRef.current?.focus(), 100))} onLayout={
IS_IOS
? () => setTimeout(() => innerRef.current?.focus(), 100)
: undefined
}
autoFocus={IS_ANDROID} autoFocus={IS_ANDROID}
accessible accessible
accessibilityLabel={label} accessibilityLabel={label}
+8 -8
View File
@@ -1,12 +1,12 @@
import {useRef} from 'react' import {useState} from 'react'
import {Animated} from 'react-native' import {Animated} from 'react-native'
export function useAnimatedValue(initialValue: number) { export function useAnimatedValue(initialValue: number) {
const lazyRef = useRef<Animated.Value>(undefined) /*
* A lazy `useState` initialiser rather than a lazily-populated ref: both
if (lazyRef.current === undefined) { * construct once and keep the same instance, but reading a ref during render
lazyRef.current = new Animated.Value(initialValue) * is a Rules of React violation.
} */
const [value] = useState(() => new Animated.Value(initialValue))
return lazyRef.current return value
} }
+3 -3
View File
@@ -1,4 +1,4 @@
import {useEffect, useRef, useState} from 'react' import {useEffect, useState} from 'react'
import {AppState, type AppStateStatus} from 'react-native' import {AppState, type AppStateStatus} from 'react-native'
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister' import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
import { import {
@@ -168,8 +168,8 @@ function QueryProviderInner({
children: React.ReactNode children: React.ReactNode
currentDid: string | undefined currentDid: string | undefined
}) { }) {
const initialDid = useRef(currentDid) const [initialDid] = useState(currentDid)
if (currentDid !== initialDid.current) { if (currentDid !== initialDid) {
throw Error( throw Error(
'Something is very wrong. Expected did to be stable due to key above.', 'Something is very wrong. Expected did to be stable due to key above.',
) )
+3 -4
View File
@@ -2,9 +2,9 @@ import {
createContext, createContext,
useContext, useContext,
useEffect, useEffect,
useEffectEvent,
useMemo, useMemo,
useReducer, useReducer,
useRef,
} from 'react' } from 'react'
import {useCurrentConvoId} from './current-convo-id' import {useCurrentConvoId} from './current-convo-id'
@@ -44,8 +44,7 @@ export function useMessageDraft() {
export function useSaveMessageDraft(message: string) { export function useSaveMessageDraft(message: string) {
const {currentConvoId} = useCurrentConvoId() const {currentConvoId} = useCurrentConvoId()
const {dispatch} = useMessageDraftsContext() const {dispatch} = useMessageDraftsContext()
const messageRef = useRef(message) const getMessage = useEffectEvent(() => message)
messageRef.current = message
useEffect(() => { useEffect(() => {
return () => { return () => {
@@ -53,7 +52,7 @@ export function useSaveMessageDraft(message: string) {
dispatch({ dispatch({
type: 'set', type: 'set',
convoId: currentConvoId, convoId: currentConvoId,
draft: messageRef.current, draft: getMessage(),
}) })
} }
} }