具有动画逻辑和进度传递功能的反应(本机)高阶组件

问题描述 投票:0回答:1

当前,我有多个视图可以通过下拉手势关闭。向下拖动时,视图会变小,直到到达我在导航器上调用goBack()的位置,将其完全关闭。

现在,由于我不想一遍又一遍地在许多文件中实现此逻辑,因此我尝试创建一个HoC来编写一次关闭动画逻辑,并使其他组件专注于其特定任务。我还想将dismissAnimationProgress值传递给包装的组件,以便它们可以在用户向下拖动时处理一些额外的逻辑(例如使某些东西褪色)。

这是我的DismissableView.tsx

export interface DismissableViewProps {
    dismissProgress: Reanimated.Value<number>;
}

export default function DismissableView<TView extends React.Component<TViewProps>, TViewProps extends DismissableViewProps>(
    WrappedComponent: TView,
    props: TViewProps,
): React.ReactElement {
    const { navigation, ...passThroughProps } = props;

    const navigateBack = useMemo(() => navigation.pop(), [navigation]);
    const gestureHandler = usePanGestureHandler();
    const dismissAnimationProgress = useValue(0); // Animation from 0 -> 1, where 1 is dismiss.
    const cardBorderRadius = useMemo(() => {
        return Reanimated.interpolate(dismissAnimationProgress, {
            inputRange: [0, 1],
            outputRange: [0, 30],
            extrapolate: Extrapolate.CLAMP,
        });
    }, [dismissAnimationProgress]);
    const viewScale = useMemo(() => {
        return Reanimated.interpolate(dismissAnimationProgress, {
            inputRange: [0, 1],
            outputRange: [1, 0.8],
            extrapolate: Extrapolate.CLAMP,
        });
    }, [dismissAnimationProgress]);
    useCode(
        () => [
            cond(eq(gestureHandler.state, State.ACTIVE), [
                set(
                    dismissAnimationProgress,
                    Reanimated.interpolate(gestureHandler.translation.y, {
                        inputRange: [0, SCREEN_HEIGHT * 0.2],
                        outputRange: [0, 1],
                    }),
                ),
            ]),
            cond(eq(gestureHandler.state, State.END), [
                set(dismissAnimationProgress, timing({ from: dismissAnimationProgress, to: 0, duration: 200, easing: Easing.out(Easing.ease) })),
            ]),
            cond(greaterOrEq(dismissAnimationProgress, 1), [call([], navigateBack)]),
        ],
        [],
    );
    const viewStyle = useMemo(() => {
        return { transform: [{ scale: viewScale, borderRadius: cardBorderRadius }] };
    }, [viewScale, cardBorderRadius]);

    return (
        <PanGestureHandler {...gestureHandler.gestureHandler}>
            <Reanimated.View style={viewStyle}>
                <WrappedComponent {...passThroughProps} navigation={navigation} dismissAnimationProgress={dismissAnimationProgress} />
            </Reanimated.View>
        </PanGestureHandler>
    );
}

这不会按预期方式工作,因为不会传递组件的属性(因为不会在参数中提供它们的属性,并且也不会设置dismissAnimationProgress道具。

在我的导航器(@react-navigation/stack)中,我像这样使用它:

import ProfileScreen from '../screens/social/ProfileScreen';
import DismissableView from '../components/DismissableView';

                                 // No parameter for props here
const DismissableProfileScreen = DismissableView(ProfileScreen);

                                  // Props include { route, navigation } for "ProfileScreen"
const Stack = createStackNavigator<MainStackNavigatorProps>();
export default function MainStackNavigator(): JSX.Element {
  return ( 
    <Stack.Navigator>
      <Stack.Screen name="ProfileScreen" component={DismissableProfileScreen} />
    </Stack.Navigator> );
}
javascript reactjs react-native react-navigation higher-order-components
1个回答
0
投票

因为您要声明HOC,所以实际上您需要将DismissableView声明为“自己”及其将接收的组件的父组件-

const dismissableView = <TView extends object>(Component: React.ComponentType<P>) =>
  const DismissableView: React.FC<TView & DismissableViewProps> = props => {

另一种方法是将DismissableView视为


const withDismissableScreen = Component => <DismissableView> <Component/> </DismissableView>;


<Stack.Screen name="ProfileScreen" component={withDismissableScreen(ProfileScreen)} />

现在DismissableScreen的声明仍将在一行中,但是您可以通过props.children获得该组件

© www.soinside.com 2019 - 2024. All rights reserved.