fix: fix getNativeScrollRef return type for FlatList (#54735)

Summary:
### The Problem

When trying to measure the location of a View within a FlatList (ie. for scrolling to the view), the current recommended method is to use measureLayout on the nested view to determine its location inside the containing FlatList:

```
const MyComponent = () => {
  const flatListRef = useRef<FlatList>(null);
  const nestedViewRef = useRef<View>(null);

  const scrollToNestedView = () => {
    if (!flatListRef.current || !nestedViewRef.current) {
      return;
    }

    nestedViewRef.current.measureLayout(
      flatListRef.current.getNativeScrollRef(),
      (x, y) => { flatListRef.current.scrollTo({ y, animated: true }); },
    );
  }

  return (
    <FlatList ref={flatListRef}>
      <View ref={nestedViewRef}>
        { /* content */ }
      </View>
    </FlatList>
  );
}
```

However the types for `FlatList` `getNativeScrollRef` don't allow this.

### The solution

This solution is basically identical to that in https://github.com/facebook/react-native/issues/52203. The return value for `getNativeScrollRef` should be `HostInstance | null`

## Changelog:[GENERAL] [FIXED] - Change FlatList.getNativeScrollRef return type definition to allow accessing the underlying HostInstance.

Pull Request resolved: https://github.com/facebook/react-native/pull/54735

Test Plan: None needed. This is only a type update exposing existing functionality.

Reviewed By: zeyap

Differential Revision: D104393366

Pulled By: huntie

fbshipit-source-id: 700f708d9a39b16af3e0ed90a748051361101627
This commit is contained in:
Jani Kinnunen
2026-05-11 07:15:42 -07:00
committed by meta-codesync[bot]
parent e2e655385c
commit 5162816e03
2 changed files with 58 additions and 43 deletions
@@ -264,7 +264,7 @@ interface ScrollResponderMixin extends SubscribableMixin {
* down to make it meet the keyboard's top. Default is false.
*/
scrollResponderScrollNativeHandleToKeyboard(
nodeHandle: any,
nodeHandle: number | HostInstance,
additionalOffset?: number,
preventNegativeScrollOffset?: boolean,
): void;
@@ -836,10 +836,29 @@ export interface ScrollViewProps
StickyHeaderComponent?: React.ComponentType<any> | undefined;
}
declare class ScrollViewComponent extends React.Component<ScrollViewProps> {}
export declare const ScrollViewBase: Constructor<ScrollResponderMixin> &
typeof ScrollViewComponent;
export class ScrollView extends ScrollViewBase {
export interface ScrollViewScrollToOptions {
x?: number | undefined;
y?: number | undefined;
animated?: boolean | undefined;
}
// Public methods for ScrollView
export interface ScrollViewImperativeMethods {
/**
* Returns a reference to the underlying scroll responder, which supports
* operations like `scrollTo`. All ScrollView-like components should
* implement this method so that they can be composed while providing access
* to the underlying scroll responder's methods.
*/
readonly getScrollResponder: () => ScrollResponderType;
readonly getScrollableNode: () => number | undefined;
readonly getInnerViewNode: () => number | undefined;
readonly getInnerViewRef: () => React.ComponentRef<typeof View> | null;
/**
* Returns a reference to the underlying native scroll view, or null if the
* native instance is not mounted.
*/
readonly getNativeScrollRef: () => HostInstance | null;
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
* Syntax:
@@ -850,18 +869,11 @@ export class ScrollView extends ScrollViewBase {
* the function also accepts separate arguments as an alternative to the options object.
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/
scrollTo(
y?:
| number
| {
x?: number | undefined;
y?: number | undefined;
animated?: boolean | undefined;
},
readonly scrollTo: (
options?: ScrollViewScrollToOptions | number,
deprecatedX?: number,
deprecatedAnimated?: boolean,
): void;
) => void;
/**
* A helper function that scrolls to the end of the scrollview;
* If this is a vertical ScrollView, it scrolls to the bottom.
@@ -870,32 +882,39 @@ export class ScrollView extends ScrollViewBase {
* The options object has an animated prop, that enables the scrolling animation or not.
* The animated prop defaults to true
*/
scrollToEnd(options?: {animated?: boolean | undefined}): void;
readonly scrollToEnd: (options?: ScrollViewScrollToOptions | null) => void;
/**
* Displays the scroll indicators momentarily.
*/
flashScrollIndicators(): void;
readonly flashScrollIndicators: () => void;
scrollResponderZoomTo(
rect: {
x: number;
y: number;
width: number;
height: number;
animated?: boolean | undefined;
},
animated?: boolean, // deprecated, put this inside the rect argument instead
): void;
scrollResponderScrollNativeHandleToKeyboard(
nodeHandle: number | HostInstance,
additionalOffset?: number,
preventNegativeScrollOffset?: boolean,
): void;
}
/**
* Returns a reference to the underlying scroll responder, which supports
* operations like `scrollTo`. All ScrollView-like components should
* implement this method so that they can be composed while providing access
* to the underlying scroll responder's methods.
*/
getScrollResponder(): ScrollResponderMixin;
export type ScrollResponderType = ScrollViewImperativeMethods;
getScrollableNode(): any;
// Undocumented
getInnerViewNode(): any;
/**
* Returns a reference to the underlying native scroll view, or null if the
* native instance is not mounted.
*/
getNativeScrollRef: () => HostInstance | null;
export interface PublicScrollViewInstance
extends HostInstance,
ScrollViewImperativeMethods {}
declare class ScrollViewComponent extends React.Component<ScrollViewProps> {}
export declare const ScrollViewBase: Constructor<ScrollResponderMixin> &
typeof ScrollViewComponent;
export interface ScrollView extends ScrollViewImperativeMethods {}
export class ScrollView extends ScrollViewBase {
/**
* @deprecated Use scrollTo instead
*/
+4 -8
View File
@@ -14,10 +14,9 @@ import type {
VirtualizedListProps,
ViewabilityConfig,
} from '@react-native/virtualized-lists';
import type {ScrollViewComponent} from '../Components/ScrollView/ScrollView';
import type {PublicScrollViewInstance} from '../Components/ScrollView/ScrollView';
import type {StyleProp} from '../StyleSheet/StyleSheet';
import type {ViewStyle} from '../StyleSheet/StyleSheetTypes';
import type {View} from '../Components/View/View';
export interface FlatListProps<ItemT> extends VirtualizedListProps<ItemT> {
/**
@@ -229,13 +228,10 @@ export abstract class FlatListComponent<
getScrollResponder: () => React.JSX.Element | null | undefined;
/**
* Provides a reference to the underlying host component
* Returns a reference to the underlying native scroll view, or null if the
* native instance is not mounted.
*/
getNativeScrollRef: () =>
| React.ComponentRef<typeof View>
| React.ComponentRef<typeof ScrollViewComponent>
| null
| undefined;
getNativeScrollRef: () => PublicScrollViewInstance | null;
getScrollableNode: () => any;