diff --git a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js index fc330dfd5c5..39260c22dff 100644 --- a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js +++ b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js @@ -1931,19 +1931,22 @@ function createRefForwarder( return state; } +// TODO: After upgrading to React 19, remove `forwardRef` from this component. // NOTE: This wrapper component is necessary because `ScrollView` is a class // component and we need to map `ref` to a differently named prop. This can be // removed when `ScrollView` is a functional component. -function Wrapper({ - ref, - ...props -}: { - ...Props, - ref: React.RefSetter, -}): React.Node { - return ; -} +const Wrapper = React.forwardRef(function Wrapper( + props: Props, + ref: ?React.RefSetter, +): React.Node { + return ref == null ? ( + + ) : ( + + ); +}); Wrapper.displayName = 'ScrollView'; +// $FlowExpectedError[prop-missing] Wrapper.Context = ScrollViewContext; module.exports = ((Wrapper: $FlowFixMe): React.AbstractComponent< diff --git a/packages/react-native/src/private/components/HScrollViewNativeComponents.js b/packages/react-native/src/private/components/HScrollViewNativeComponents.js index e335f53b780..9772dccb39d 100644 --- a/packages/react-native/src/private/components/HScrollViewNativeComponents.js +++ b/packages/react-native/src/private/components/HScrollViewNativeComponents.js @@ -21,33 +21,34 @@ import Platform from '../../../Libraries/Utilities/Platform'; import AndroidHorizontalScrollContentViewNativeComponent from '../specs/components/AndroidHorizontalScrollContentViewNativeComponent'; import useSyncOnScroll from './useSyncOnScroll'; import * as React from 'react'; +import {forwardRef} from 'react'; const HScrollViewNativeComponentForPlatform = Platform.OS === 'android' ? AndroidHorizontalScrollViewNativeComponent : ScrollViewNativeComponent; +// TODO: After upgrading to React 19, remove `forwardRef` from this component. export const HScrollViewNativeComponent: React.AbstractComponent< ScrollViewNativeProps, TScrollViewNativeImperativeHandle, // $FlowExpectedError[incompatible-type] - Flow cannot model imperative handles, yet. -> = function HScrollViewNativeComponent(props: { - ...ScrollViewNativeProps, - ref?: React.RefSetter, - ... -}): React.Node { - const [ref, enableSyncOnScroll] = useSyncOnScroll(props.ref); +> = forwardRef(function HScrollViewNativeComponent( + props: ScrollViewNativeProps, + ref: ?React.RefSetter, +): React.Node { + const [componentRef, enableSyncOnScroll] = useSyncOnScroll(ref); // NOTE: When `useSyncOnScroll` triggers an update, `props` will not have // changed. Notably, `props.children` will be the same, allowing React to // bail out during reconciliation. return ( ); -}; +}); export const HScrollContentViewNativeComponent: HostComponent = Platform.OS === 'android' diff --git a/packages/react-native/src/private/components/VScrollViewNativeComponents.js b/packages/react-native/src/private/components/VScrollViewNativeComponents.js index 57d9ba5bda0..89d17271f5b 100644 --- a/packages/react-native/src/private/components/VScrollViewNativeComponents.js +++ b/packages/react-native/src/private/components/VScrollViewNativeComponents.js @@ -20,28 +20,29 @@ import View from '../../../Libraries/Components/View/View'; import Platform from '../../../Libraries/Utilities/Platform'; import useSyncOnScroll from './useSyncOnScroll'; import * as React from 'react'; +import {forwardRef} from 'react'; +// TODO: After upgrading to React 19, remove `forwardRef` from this component. export const VScrollViewNativeComponent: React.AbstractComponent< ScrollViewNativeProps, TScrollViewNativeImperativeHandle, // $FlowExpectedError[incompatible-type] - Flow cannot model imperative handles, yet. -> = function VScrollViewNativeComponent(props: { - ...ScrollViewNativeProps, - ref?: React.RefSetter, - ... -}): React.Node { - const [ref, enableSyncOnScroll] = useSyncOnScroll(props.ref); +> = forwardRef(function VScrollViewNativeComponent( + props: ScrollViewNativeProps, + ref: ?React.RefSetter, +): React.Node { + const [componentRef, enableSyncOnScroll] = useSyncOnScroll(ref); // NOTE: When `useSyncOnScroll` triggers an update, `props` will not have // changed. Notably, `props.children` will be the same, allowing React to // bail out during reconciliation. return ( ); -}; +}); export const VScrollContentViewNativeComponent: HostComponent = Platform.OS === 'android' ? View : ScrollContentViewNativeComponent;