Skip to content

Commit

Permalink
Define debugging name for multiple components
Browse files Browse the repository at this point in the history
Summary:
This cleans up some dead code in animated components (some wrappers that actually don't do anything), which in this case leads to component names being properly defined for debugging in React DevTools, etc.

Changelog: [internal]

Differential Revision: D51401568
  • Loading branch information
rubennorte authored and facebook-github-bot committed Nov 16, 2023
1 parent 5730f56 commit c756dd1
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,7 @@ import FlatList from '../../Lists/FlatList';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';

/**
* @see https://github.com/facebook/react-native/commit/b8c8562
*/
const FlatListWithEventThrottle = React.forwardRef(
// $FlowFixMe[incompatible-call]
(
props: React.ElementConfig<typeof FlatList>,
ref:
| ((null | FlatList<mixed>) => mixed)
| {current: null | FlatList<mixed>, ...},
) => <FlatList {...props} ref={ref} />,
);

export default (createAnimatedComponent(
FlatListWithEventThrottle,
): AnimatedComponentType<
export default (createAnimatedComponent(FlatList): AnimatedComponentType<
React.ElementConfig<typeof FlatList>,
React.ElementRef<typeof FlatList>,
>);
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,44 @@ type Instance = React.ElementRef<typeof ScrollView>;
* @see https://github.com/facebook/react-native/commit/b8c8562
*/
const AnimatedScrollView: AnimatedComponentType<Props, Instance> =
React.forwardRef((props, forwardedRef) => {
// (Android only) When a ScrollView has a RefreshControl and
// any `style` property set with an Animated.Value, the CSS
// gets incorrectly applied twice. This is because ScrollView
// swaps the parent/child relationship of itself and the
// RefreshControl component (see ScrollView.js for more details).
if (
Platform.OS === 'android' &&
props.refreshControl != null &&
props.style != null
React.forwardRef(
function AnimatedScrollViewWithOrWithoutInvertedRefreshControl(
props,
forwardedRef,
) {
return (
<AnimatedScrollViewWithInvertedRefreshControl
scrollEventThrottle={0.0001}
{...props}
ref={forwardedRef}
refreshControl={props.refreshControl}
/>
);
} else {
return (
<AnimatedScrollViewWithoutInvertedRefreshControl
scrollEventThrottle={0.0001}
{...props}
ref={forwardedRef}
/>
);
}
});
// (Android only) When a ScrollView has a RefreshControl and
// any `style` property set with an Animated.Value, the CSS
// gets incorrectly applied twice. This is because ScrollView
// swaps the parent/child relationship of itself and the
// RefreshControl component (see ScrollView.js for more details).
if (
Platform.OS === 'android' &&
props.refreshControl != null &&
props.style != null
) {
return (
<AnimatedScrollViewWithInvertedRefreshControl
scrollEventThrottle={0.0001}
{...props}
ref={forwardedRef}
refreshControl={props.refreshControl}
/>
);
} else {
return (
<AnimatedScrollViewWithoutInvertedRefreshControl
scrollEventThrottle={0.0001}
{...props}
ref={forwardedRef}
/>
);
}
},
);

const AnimatedScrollViewWithInvertedRefreshControl = React.forwardRef(
// $FlowFixMe[incompatible-call]
(
function AnimatedScrollViewWithInvertedRefreshControl(
props: {
...React.ElementConfig<typeof ScrollView>,
// $FlowFixMe[unclear-type] Same Flow type as `refreshControl` in ScrollView
Expand All @@ -71,7 +76,7 @@ const AnimatedScrollViewWithInvertedRefreshControl = React.forwardRef(
forwardedRef:
| {current: Instance | null, ...}
| ((Instance | null) => mixed),
) => {
) {
// Split `props` into the animate-able props for the parent (RefreshControl)
// and child (ScrollView).
const {intermediatePropsForRefreshControl, intermediatePropsForScrollView} =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,13 @@
* @format
*/

import type {SectionBase} from '../../Lists/SectionList';
import type {AnimatedComponentType} from '../createAnimatedComponent';

import SectionList from '../../Lists/SectionList';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';

/**
* @see https://github.com/facebook/react-native/commit/b8c8562
*/
const SectionListWithEventThrottle = React.forwardRef(
// $FlowFixMe[incompatible-call]
(
props: React.ElementConfig<typeof SectionList>,
ref:
| ((null | SectionList<SectionBase<$FlowFixMe>>) => mixed)
| {
current: null | SectionList<SectionBase<$FlowFixMe>>,
...
},
) => <SectionList {...props} ref={ref} />,
);

export default (createAnimatedComponent(
SectionListWithEventThrottle,
): AnimatedComponentType<
export default (createAnimatedComponent(SectionList): AnimatedComponentType<
React.ElementConfig<typeof SectionList>,
React.ElementRef<typeof SectionList>,
>);
83 changes: 44 additions & 39 deletions packages/react-native/Libraries/Animated/createAnimatedComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,55 @@ import useMergeRefs from '../Utilities/useMergeRefs';
import useAnimatedProps from './useAnimatedProps';
import * as React from 'react';

export type AnimatedProps<Props: {...}> = $ObjMap<
Props &
$ReadOnly<{
passthroughAnimatedPropExplicitValues?: React.ElementConfig<typeof View>,
}>,
() => any,
>;

export type AnimatedComponentType<
-Props: {+[string]: mixed, ...},
Props: {...},
+Instance = mixed,
> = React.AbstractComponent<
$ObjMap<
Props &
$ReadOnly<{
passthroughAnimatedPropExplicitValues?: React.ElementConfig<
typeof View,
>,
}>,
() => any,
>,
Instance,
>;
> = React.AbstractComponent<AnimatedProps<Props>, Instance>;

export default function createAnimatedComponent<TProps: {...}, TInstance>(
Component: React.AbstractComponent<TProps, TInstance>,
): AnimatedComponentType<TProps, TInstance> {
return React.forwardRef((props, forwardedRef) => {
const [reducedProps, callbackRef] = useAnimatedProps<TProps, TInstance>(
const AnimatedComponent = React.forwardRef<AnimatedProps<TProps>, TInstance>(
(props, forwardedRef) => {
const [reducedProps, callbackRef] = useAnimatedProps<TProps, TInstance>(
// $FlowFixMe[incompatible-call]
props,
);
// $FlowFixMe[incompatible-call]
props,
);
// $FlowFixMe[incompatible-call]
const ref = useMergeRefs<TInstance | null>(callbackRef, forwardedRef);

// Some components require explicit passthrough values for animation
// to work properly. For example, if an animated component is
// transformed and Pressable, onPress will not work after transform
// without these passthrough values.
// $FlowFixMe[prop-missing]
const {passthroughAnimatedPropExplicitValues, style} = reducedProps;
const {style: passthroughStyle, ...passthroughProps} =
passthroughAnimatedPropExplicitValues ?? {};
const mergedStyle = {...style, ...passthroughStyle};

return (
<Component
{...reducedProps}
{...passthroughProps}
style={mergedStyle}
ref={ref}
/>
);
});
const ref = useMergeRefs<TInstance | null>(callbackRef, forwardedRef);

// Some components require explicit passthrough values for animation
// to work properly. For example, if an animated component is
// transformed and Pressable, onPress will not work after transform
// without these passthrough values.
// $FlowFixMe[prop-missing]
const {passthroughAnimatedPropExplicitValues, style} = reducedProps;
const {style: passthroughStyle, ...passthroughProps} =
passthroughAnimatedPropExplicitValues ?? {};
const mergedStyle = {...style, ...passthroughStyle};

return (
<Component
{...reducedProps}
{...passthroughProps}
style={mergedStyle}
ref={ref}
/>
);
},
);

AnimatedComponent.displayName = `Animated(${
Component.displayName || 'Anonymous'
})`;

return AnimatedComponent;
}

0 comments on commit c756dd1

Please sign in to comment.