feat: add `usePager` hook
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
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)
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
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
usePagerViewhook
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>
);
};