diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index c344aadab61..74e6001241f 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -706,6 +706,17 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + deferFlatListFocusChangeRenderUpdate: { + defaultValue: false, + metadata: { + dateAdded: '2025-07-02', + description: + 'Use the deferred cell render update mechanism for focus change in FlatList.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, disableInteractionManager: { defaultValue: true, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 9989d78d7dd..f5720762666 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<670f6eab8583db989988cbf1a28383a2>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -33,6 +33,7 @@ export type ReactNativeFeatureFlagsJsOnly = $ReadOnly<{ animatedShouldDebounceQueueFlush: Getter, animatedShouldUseSingleOp: Getter, avoidStateUpdateInAnimatedPropsMemo: Getter, + deferFlatListFocusChangeRenderUpdate: Getter, disableInteractionManager: Getter, enableAccessToHostTreeInFabric: Getter, fixVirtualizeListCollapseWindowSize: Getter, @@ -135,6 +136,11 @@ export const animatedShouldUseSingleOp: Getter = createJavaScriptFlagGe */ export const avoidStateUpdateInAnimatedPropsMemo: Getter = createJavaScriptFlagGetter('avoidStateUpdateInAnimatedPropsMemo', true); +/** + * Use the deferred cell render update mechanism for focus change in FlatList. + */ +export const deferFlatListFocusChangeRenderUpdate: Getter = createJavaScriptFlagGetter('deferFlatListFocusChangeRenderUpdate', false); + /** * Disables InteractionManager and replaces its scheduler with `setImmediate`. */ diff --git a/packages/virtualized-lists/Lists/VirtualizedList.js b/packages/virtualized-lists/Lists/VirtualizedList.js index d9764aa0ace..5b8aaa525bd 100644 --- a/packages/virtualized-lists/Lists/VirtualizedList.js +++ b/packages/virtualized-lists/Lists/VirtualizedList.js @@ -64,6 +64,7 @@ import { View, findNodeHandle, } from 'react-native'; +import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags'; export type {ListRenderItemInfo, ListRenderItem, Separators}; @@ -1332,7 +1333,12 @@ class VirtualizedList extends StateSafePureComponent< _onCellFocusCapture = (cellKey: string) => { this._lastFocusedCellKey = cellKey; - this._updateCellsToRender(); + if (ReactNativeFeatureFlags.deferFlatListFocusChangeRenderUpdate()) { + // Schedule the cells to render update the same way we handle scroll or layout events. + this._scheduleCellsToRenderUpdate(); + } else { + this._updateCellsToRender(); + } }; _onCellUnmount = (cellKey: string) => {