Repository navigation
THE VIEW WITHIN THE MODAL in the PaystackProvider.tsx doesn't show #220
Description
Activity
I TOOK THE ISSUE TO CHATGPT BUT NONE OF THE SOLUTIONS BELOW WORKED
THE WEBVIEW TRYING TO RENDER BEFORE THE MODAL OPENS
So I took the issue to CHATGPT with the prompt :
In my expo app, I have a package that uses webview from react-native-webview. I have a function to call to open up the webpage , which is inside a modal from react native. When it opens up, the modal opens, but the view within it does not show until I change a style and then the UI hydrates then it shows up. What happens during react hydration and why doesn't it show first time? How can I solve this issue?.I got replies stating that the issue is caused by the modal not being ready when webView mounts and it proposed solutions which entail delaying the webView render until after the modal is ready
const [modalVisible, setModalVisible] = useState(false); const [showWebView, setShowWebView] = useState(false); const openModal = () => { setModalVisible(true); // Delay WebView render slightly setTimeout(() => { setShowWebView(true); }, 100); // Try increasing to 200ms if needed };
Then in the component
<Modal visible={modalVisible} transparent={false} animationType="slide"> <View style={{ flex: 1 }}> {showWebView && ( <WebView source={{ uri: 'https://example.com' }} style={{ flex: 1 }} /> )} </View> </Modal>
It suggested another solution to force layout updates :
<WebView source={{ uri: 'https://example.com' }} style={{ flex: 1 }} onLayout={() => { // Sometimes triggers rendering if layout wasn’t complete console.log('WebView layout complete'); }} />
I don't know if this helps but I've been stuck on this issue now since yesterday and it's delaying progress
I have tried conditionally rendering both the parent View component as well as the webView component all to no avail.
Are there real people who use this package in production? Am I the only one with this issue?
@AMUZYZOHO i believe you are having the same issue as me right? #217
In my case the modal also opens but its completely blank (White screen) ?
@Tamer7 On mine the white screen doesn't show. the transparent modal just opens up and that's it. To get the payment screen to then show, I have to go to the PaystackProvider.js file in the node_modules folder and then make a change and save, then the ui refreshes and the payment screen finally opens. This isn't meant to be, it's just so wrong
honestly I think the Payment ui webview should be removed from the modal and placed in it's own dedicated screen
@just1and0 Please is there anyone that's going to look into this? Is there any alternative paystack package for react-native we can use in the meantime?
@AMUZYZOHO agreed, i would also like to know if there are any alternatives as my app is going live soon and its basically useless without payment integration, i might even just ditch paystack and use another provider at this point.
@Tamer7 My bro. I just created a fresh expo project and used the package and I GOT THE SAME ISSUE !
It seems it don't work with fresh, newer expo apps. I'm so confused as to how the v5 was tested and approved for publishing.
Someone on YouTube used it and it worked, though it appears he used an older version of expo.
Check HERE for the YouTube video.
@Tamer7 Share me your Whatsapp no, or message me on 08188331664 so we can have more conversations. I'm thinking of looking for other payment options too as this has delayed my progressHi @AMUZYZOHO and @Tamer7,
Thanks for raising this issue and sharing your debugging steps and frustrations. I understand it can be stressful when you’re facing a blocker like this, especially if you’re working on a production app.
To clarify, this project is maintained by volunteers in their free time. While we do our best to keep it working with the latest updates, we’re not sponsored by Paystack or any organization—it’s a labor of love for the community.
I’m sorry you’re experiencing this issue with newer Expo versions. If you discover a solution or workaround that can help others, please feel free to open a pull request or share your steps here. It’s through collective contributions that this project has grown over the years.
Regarding your suggestion to move the WebView to a dedicated screen: that’s an interesting idea. If you’d like to explore that, please feel free to propose it or prototype it. We always welcome PRs.
One quick note: for your own privacy and security, please avoid sharing your personal phone number or other sensitive information publicly on GitHub. Let’s keep communication here or in dedicated project channels to protect everyone involved.
Finally, while it’s natural to explore alternatives when things don’t work out, I ask that we keep the conversation respectful to the efforts of everyone who’s contributed to this package.
Let’s work together to find a fix for this!
Cheers 🥂
Reacted by TamerNo problem brother @just1and0 . I'm still searching for ways to solve it. I'm certain @Tamer7 is as well, if I get a breakthrough I'd definitely share
Reacted by Tamer, Oluwatobi Shokunbi and AMUZYZOHO@just1and0 @Tamer7 Okay I've got good news. I figured how to make it work now and it's worked repeatedly for me now without issues. So for those that initialized their expo project using a blank template (no expo router) they are able to use the react-native-paystack-webview package as it is.
But for those that initialized their expo project having expo-router (having _layout.tsx and index.tsx), we have to use the PaystackProvider context within the expo-router's file-based modal. In other words we shouldn't wrap our entire application with the PaystackProvider, we should just wrap the component within the modal only and it'd work . I'd share some code in a bit so just stay tuned.Reacted by Oluwatobi ShokunbiReacted by Oluwatobi ShokunbiThis is awesome to hear!
Thanks for doubling down and figuring it out!It will be nice to create a PR and add this to the readme, on the installation guide, so folks using expo router are aware of this behaviour.
In this example, I created a fresh expo project to test with.
So to do this, first create a 'modal.tsx' file in the root of your /app directory. Has to be 'modal.tsx' as that's the file-naming convention with expo.
Then in your modal.tsx file, You can have this- app/modal.tsx
import usePaystackPay from "@/hooks/usePaystackPay"; import { useIsFocused } from "@react-navigation/native"; import { useRouter } from "expo-router"; import { useEffect } from "react"; import { PaystackProvider } from "react-native-paystack-webview"; const PaystackCallComponent = () => { const { payNow } = usePaystackPay({ email: "anita@gmail.com" }); const isFocused = useIsFocused(); useEffect(() => { if (isFocused) payNow(); }, []); return <></>; }; export default function ModalScreen() { const router = useRouter(); return ( <PaystackProvider publicKey="pk_test_8cb12f0c166ce80e06eb9a87857bd4b9ef8534a7" debug currency="NGN" onGlobalCancel={() => router.push("/")} > <PaystackCallComponent /> </PaystackProvider> ); }
NOTE: I'm using the
import { useIsFocused } from "@react-navigation/native";to check if the modal screen is in focus before running the payNow function to prevent unsolicited function calls. I'm usingrouter.push("/")to go back to the previous page after the transaction is cancelled. You could as well userouter.back(). You can also do the same or set a a global "paymentConfirmed" state to true if you're using a global state management tool like zustand e.t.c, in theonGlobalSuccessafter a successfull transaction.For the
usePaystackPayhook, I have this ;- hooks/usePaystackPay
import { usePaystack } from "react-native-paystack-webview"; interface PaystackPayProps { email: string; } const usePaystackPay = ({ email }: PaystackPayProps) => { const { popup } = usePaystack(); const payNow = () => popup.checkout({ email: email || "jane.doe@example.com", amount: 15000, reference: `TXN_${Math.floor(Math.random() * 1000000)}`, // plan: "PLN_example123", invoice_limit: 3, // subaccount: "SUB_abc123", // split_code: "SPL_def456", // split: { // type: "percentage", // bearer_type: "account", // subaccounts: [ // { subaccount: "ACCT_abc", share: "60" }, // { subaccount: "ACCT_xyz", share: "40" }, // ], // }, metadata: { custom_fields: [ { display_name: "Order ID", variable_name: "order_id", value: "OID1234", }, ], }, onSuccess: (res) => console.log("Payment Success:", res), onCancel: () => console.log("User cancelled payment"), onLoad: (res) => console.log("WebView Loaded:", res), onError: (err) => console.log("WebView Error:", err), }); return { payNow }; }; export default usePaystackPay;
I only have an email prop here , but you could add more like the amount, reference, plan e.t.c A better thing to do would be to pass those props to the
payNowfunction rather than directly to the hookIn your
- app/_layout.tsx
Add the stack screen for the
modal.tsx, use any presentation style you like. You can have this ;import { DarkTheme, DefaultTheme, ThemeProvider, } from "@react-navigation/native"; import { useFonts } from "expo-font"; import { Stack } from "expo-router"; import { StatusBar } from "expo-status-bar"; import "react-native-reanimated"; import { useColorScheme } from "@/hooks/useColorScheme"; export default function RootLayout() { const colorScheme = useColorScheme(); const [loaded] = useFonts({ SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"), }); if (!loaded) { // Async font loading only occurs in development. return null; } return ( <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}> <Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> <Stack.Screen name="+not-found" /> <Stack.Screen name="modal" options={{ headerShown: false, presentation: "modal" }} /> </Stack> <StatusBar style="auto" /> </ThemeProvider> ); }
NOTE: Never use "formSheet" as the presentation for the modal, use "modal". I discovered that if you use formSheet, and you minimize the application and reopen, the app will crash. Stick to "modal"
Finally, to make the call to pay, I'm using useRouter hook from expo router to just navigate to the modal route and then just have a useEffect call the payNow function. I have this in my homepage ;
import { Image } from "expo-image"; import { StyleSheet, TouchableOpacity } from "react-native"; import ParallaxScrollView from "@/components/ParallaxScrollView"; import { ThemedText } from "@/components/ThemedText"; import { useRouter } from "expo-router"; export default function HomeScreen() { const router = useRouter(); return ( <ParallaxScrollView headerBackgroundColor={{ light: "#A1CEDC", dark: "#1D3D47" }} headerImage={ <Image source={require("@/assets/images/partial-react-logo.png")} style={styles.reactLogo} /> } > <TouchableOpacity onPress={() => router.push("/modal")} style={{ padding: 16, borderRadius: 8, backgroundColor: "#007AFF", }} > <ThemedText type="defaultSemiBold">PAY NOW !</ThemedText> </TouchableOpacity> </ParallaxScrollView> ); } const styles = StyleSheet.create({ titleContainer: { flexDirection: "row", alignItems: "center", gap: 8, }, stepContainer: { gap: 8, marginBottom: 8, }, reactLogo: { height: 178, width: 290, bottom: 0, left: 0, position: "absolute", }, });
Ignore the ParallaxScrollView, ThemedText components as those usually come along with a new initialized expo app. The main take away from this page is that we are navigating to the modal route in the TouchableOpacity using useRouter from expo-router
To read more on expo's file-based modal, check HERE@Tamer7 Please help test it out and revert if it's worked for you? I don't know if this is okay to add to the readme file, or still requires some editing ? Please go through to see if it's cool ?
@just1and0 i created a package from your work named native-customizable-paystack-webview(https://www.npmjs.com/package/native-customizable-paystack-webview) which allows user to render the webview in a view or modal which is very important for the project i was working on at that time, so i can render the webview alongside other content on the screen i have been using this package for months now, for most of my project and i will love to see it in included in your work
https://github.com/sharafadeenhammed/native-customizable-paystack-webview@sharafadeenhammed Hmmm. That's cool. From which version of the react-native-paystack-webview did you create this?
@AMUZYZOHO I used version 4.0.5 but now they are using the CONTEXT API instead of REF to expose the api
@AMUZYZOHO I will make an update on the package very soon to support the CONTEXT API for the modal view and an alternative inline component that you can be rendered inline with other components
Reacted by Jerry NwaezeReacted by Jerry Nwaeze@sharafadeenhammed Well, good one. Not one to discourage others from doing stuff but I really don't think there's a need to revamp the whole package as it functions properly as it is.
Reacted by Oluwatobi Shokunbi@just1and0 Has there been any fixes yet?
Describe the bug
After calling payNow() , the modal opens but the view containing the webView component doesn't show
To Reproduce
Steps to reproduce the behavior:
Expected behavior
The webview component ought to render immediately after the modal opens up
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
The view eventually shows up after you make a change to the PaystackProvider.js (it's.js in production, from the node_modules folder).
When debug is set to true, I get all the logs that confirm that the webView starts load, and ends loading which shows that it mounts, but it's containing View parent just does not show up until after a change and then the UI hydrates