Skip to content

Wrapped pager for ease of use with separate components (without mapping function) #912

Open
@fendyk

Description

@fendyk

Describe the feature

This wraps the pagerview into a separate component and looks for the children within the pagerview and based on that will memoize the components.

Motivation

I struggled to find a way of using the usePagerView hook without a mapping function. For example when you want to show multiple components. So I thought of this idea and I just wanted to share this with everyone :)

Let me know what you think about this! Maybe someone else has an even better alternative? Happy coding!

Related Issues

Issue right now (look at comment):

export function PagerHookExample() {
  const { AnimatedPagerView, ref, ...rest } = usePagerView({ pagesAmount: 10 });
  
  return (
    <SafeAreaView style={styles.container}>
      <AnimatedPagerView
        testID="pager-view"
        ref={ref}
        style={styles.PagerView}
        initialPage={0}
        layoutDirection="ltr"
        overdrag={rest.overdragEnabled}
        scrollEnabled={rest.scrollEnabled}
        onPageScroll={rest.onPageScroll}
        onPageSelected={rest.onPageSelected}
        onPageScrollStateChanged={rest.onPageScrollStateChanged}
        pageMargin={10}
        orientation="horizontal"
      >
        {useMemo(
          () =>
            rest.pages.map((_, index) => ( // We're mapping here, but what if we want to show multiple components?
              <View
                testID="pager-view-content"
                key={index}
                style={{
                  flex: 1,
                  backgroundColor: '#fdc08e',
                  alignItems: 'center',
                  padding: 20,
                }}
                collapsable={false}
              >
                <LikeCount />
                <Text testID={`pageNumber${index}`}>
                  {`page number ${index}`}
                </Text>
              </View>
            )),
          [rest.pages]
        )}
      </AnimatedPagerView>
      <NavigationPanel {...rest} />
    </SafeAreaView>
  );
}

Step one: Create the component

import { forwardRef, Children, useMemo, useEffect } from "react";
import PagerView, { UsePagerViewProps } from "react-native-pager-view";

interface ListProps extends Omit<UsePagerViewProps, "ref"> {
	children: React.ReactNode;
	onListCountChange?: (count: number) => void;
}

const Pager = forwardRef<PagerView, ListProps>(
	({ children, onListCountChange, AnimatedPagerView, scrollEnabled, ...other }, ref) => {
		const childCount = Children.count(children);

		useEffect(() => {
			onListCountChange?.(childCount);
		}, [childCount]);

		return (
			<AnimatedPagerView
				useNext
				scrollEnabled={scrollEnabled || false}
				ref={ref}
				style={{ flex: 1 }}
				{...other}
			>
				{useMemo(
					() =>
						Children.map(children, (child, index) => {
							return child
						}),
					[children],
				)}
			</AnimatedPagerView>
		);
	},
);

export default Pager;

Step two: use the component using the usePagerView hook

export default function Screen() {
	const { activePage, ref, ...pagerViewProps } = usePagerView();
	return (
		<Pager
			activePage={activePage}
			ref={ref}
			{...pagerViewProps}
		>
			<UserProgressPage key={"1"} />
			<PlanStatsProgressPage key={"2"} />
			<ExerciseProgressPage key={"3"} />
		</Pager>
	);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions