From 1341169a4b4fa93b7e25945261abd2541ebb23dd Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 27 Jun 2024 11:08:11 -0700 Subject: [PATCH] RN: Remove `forwardRef` from `ScrollView` (#45197) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45197 With React 19, `forwardRef` is no longer necessary because `ref` is available on props. However, this only holds true for functional components — not class components. This eliminates the `forwardRef` invocation in `ScrollView`, while retaining the wrapper component to map `ref` to `scrollViewRef` for the class component. For now... Changelog: [Internal] Reviewed By: javache Differential Revision: D59091873 fbshipit-source-id: 60afcd441aec82fa050738b5c09083f3a26378d6 --- .../Components/ScrollView/ScrollView.js | 31 +++++++++---------- .../__snapshots__/ScrollView-test.js.snap | 1 - 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js index 0cc11288f1f..14253bff890 100644 --- a/packages/react-native/Libraries/Components/ScrollView/ScrollView.js +++ b/packages/react-native/Libraries/Components/ScrollView/ScrollView.js @@ -649,13 +649,13 @@ export type Props = $ReadOnly<{| * A ref to the inner View element of the ScrollView. This should be used * instead of calling `getInnerViewRef`. */ - innerViewRef?: ForwardedRef, + innerViewRef?: React.RefSetter, /** * A ref to the Native ScrollView component. This ref can be used to call * all of ScrollView's public methods, in addition to native methods like * measure, measureLayout, etc. */ - scrollViewRef?: ForwardedRef, + scrollViewRef?: React.RefSetter, |}>; type State = {| @@ -1891,11 +1891,9 @@ const styles = StyleSheet.create({ }, }); -type ForwardedRef = {current: null | T, ...} | ((null | T) => mixed); - type RefForwarder = { getForwardingRef: ( - ?ForwardedRef, + ?React.RefSetter, ) => (TNativeInstance | null) => void, nativeInstance: TNativeInstance | null, publicInstance: TPublicInstance | null, @@ -1933,21 +1931,22 @@ function createRefForwarder( return state; } -/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's - * LTI update could not be added via codemod */ -function Wrapper(props, ref: (mixed => mixed) | {current: mixed, ...}) { +// 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 ; } Wrapper.displayName = 'ScrollView'; -// $FlowFixMe[incompatible-call] -const ForwardedScrollView = React.forwardRef(Wrapper); +Wrapper.Context = ScrollViewContext; -// $FlowFixMe[prop-missing] Add static context to ForwardedScrollView -ForwardedScrollView.Context = ScrollViewContext; - -ForwardedScrollView.displayName = 'ScrollView'; - -module.exports = ((ForwardedScrollView: $FlowFixMe): React.AbstractComponent< +module.exports = ((Wrapper: $FlowFixMe): React.AbstractComponent< React.ElementConfig, PublicScrollViewInstance, > & diff --git a/packages/react-native/Libraries/Components/ScrollView/__tests__/__snapshots__/ScrollView-test.js.snap b/packages/react-native/Libraries/Components/ScrollView/__tests__/__snapshots__/ScrollView-test.js.snap index a605fe25bf7..44636eb9dab 100644 --- a/packages/react-native/Libraries/Components/ScrollView/__tests__/__snapshots__/ScrollView-test.js.snap +++ b/packages/react-native/Libraries/Components/ScrollView/__tests__/__snapshots__/ScrollView-test.js.snap @@ -34,7 +34,6 @@ exports[`ScrollView renders its children: should deep render when not mocked (pl onTouchMove={[Function]} onTouchStart={[Function]} pagingEnabled={false} - scrollViewRef={null} sendMomentumEvents={false} snapToEnd={true} snapToStart={true}