react-native-pager-view icon indicating copy to clipboard operation
react-native-pager-view copied to clipboard

feat: add `usePager` hook

Open gronxb opened this issue 2 years ago • 2 comments

Summary

Related Issue https://github.com/callstack/react-native-pager-view/issues/92

During my experience with react-native-pager-view, I encountered a limitation where accessing the pager view's features was predominantly dependent on using a ref. This reliance often led to less flexible and more complex implementations. Therefore, I implemented a hook for the methods.

However, I realized that simply exposing the existing methods - setPage, setPageWithoutAnimation, and setScrollEnabled - was insufficient, as there was no way to retrieve the current state information. Merely exporting these methods limited the scope of possible scenarios. Therefore, I found it necessary to include not only these methods but also values representing the current page, and flags indicating whether it's possible to move to the next or previous page.

The implementation was carried out using React Context, and components within the <PagerView /> component can now utilize these features through the usePagerView hook. This approach ensures that all child components of <PagerView /> have easy access to the pager view's capabilities.

  • Usage
const Item = () => {
  const {
    page,
    hasNextPage,
    hasPreviousPage,
    setPage,
    setPageWithoutAnimation,
    setScrollEnabled,
  } = usePagerView();

  return (
    <View style={styles.content}>
      <Text>Current Page: {page}</Text>
      <Text>hasNextPage: {String(hasNextPage)}</Text>
      <Text>hasPreviousPage: {String(hasPreviousPage)}</Text>
      <Button
        title="next page"
        onPress={() => {
          if (hasNextPage) {
            setPage(page + 1);
          }
        }}
      />
      <Button
        title="prev page"
        onPress={() => {
          if (hasPreviousPage) {
            setPage(page - 1);
          }
        }}
      />

      <Button
        title="next page without animation"
        onPress={() => {
          setPageWithoutAnimation(page + 1);
        }}
      />

      <Button
        title="setScrollEnabled to true"
        onPress={() => {
          setScrollEnabled(true);
        }}
      />

      <Button
        title="setScrollEnabled to false"
        onPress={() => {
          setScrollEnabled(false);
        }}
      />
    </View>
  );
};

https://github.com/callstack/react-native-pager-view/assets/41789633/1aaf8e04-2034-409c-a429-dfae7a4cf450

Test Plan

스크린샷 2023-12-11 오후 4 34 16 If usePagerView is not used within a component, it will throw an error for the developer's awareness.

What's required for testing (prerequisites)?

Inside the <PageView /> component, use the usePagerView hook

What are the steps to reproduce (after prerequisites)?

See Usage above

Compatibility

OS Implemented
iOS
Android

Checklist

  • [X] I have tested this on a device and a simulator
  • [X] I added the documentation in README.md
  • [X] I updated the typed files (TS and Flow)

gronxb avatar Dec 11 '23 08:12 gronxb

Hello,

I appreciate your contribution to this project. You have done a great job with your solution. 👏

I’m curious to learn more about your approach and how it differs from this approach from the example folder. Could you please explain to me what is the difference between them? I think we can both benefit from sharing our perspectives and insights. 😊

Thank you for your time and cooperation.

troZee avatar Dec 11 '23 15:12 troZee

@troZee

Thank you for your reply.

First, useNavigationPanel seems to me like a hook designed to pass refs and props to PagerView. The hook I've created utilizes the React Context, allowing PagerView to act as a Provider, and targets the use of PagerView methods in its children. Although useNavigationPanel exports methods, it must be possible to pass them to children as props.

In the production environment I am working on, children of PagerView often experience props drilling. Therefore, I wanted to support a method that could be controlled within the <PagerView /> itself.

Issue #92 was posted in the past, and from the reactions to that issue, I realized that there were quite a few people who felt the same way I did.

Although it's a different case, react-navigation also allows child components to manage page navigation scenarios through useNavigation(). I approached PagerView with the same perspective.

  • Usage usePagerView hook

const App = () => {
    return (
        <PagerView>
            <Item />
        </PagerView>
    )
}

// child

const Item = () => {
  const {
    page,
    hasNextPage,
    hasPreviousPage,
    setPage,
    setPageWithoutAnimation,
    setScrollEnabled,
  } = usePagerView();

  return (
    <View style={styles.content}>
      <Text>Current Page: {page}</Text>
      <Text>hasNextPage: {String(hasNextPage)}</Text>
      <Text>hasPreviousPage: {String(hasPreviousPage)}</Text>
      <Button
        title="next page"
        onPress={() => {
          if (hasNextPage) {
            setPage(page + 1);
          }
        }}
      />
      <Button
        title="prev page"
        onPress={() => {
          if (hasPreviousPage) {
            setPage(page - 1);
          }
        }}
      />

      <Button
        title="next page without animation"
        onPress={() => {
          setPageWithoutAnimation(page + 1);
        }}
      />

      <Button
        title="setScrollEnabled to true"
        onPress={() => {
          setScrollEnabled(true);
        }}
      />

      <Button
        title="setScrollEnabled to false"
        onPress={() => {
          setScrollEnabled(false);
        }}
      />
    </View>
  );
};

gronxb avatar Dec 12 '23 00:12 gronxb