Accepting Payments in a React Native App (Part 4)
Building the Payment Client Using React Native and React
Background
This is the fourth and final article in a series of posts about integrating Braintree payments into a JavaScript only (no native code) React Native mobile application. The GitHub repository for this project is located here.
Additionally, this project is available as the react-native-webview-braintree npm package for you to use in your own projects.
This article discusses building the final version of the client using React Native, React, JavaScript, and the version 3 of the Braintree JavaScript SDK. Since this technique builds on the previous articles in this series this post is going to be relatively short. It also means it will seem incomplete if you haven’t read the other articles prior to this one.
Those other articles can be found here:
1. Project Introduction. This section may not sound like much, but it’s a good explanation on how everything will fit together.
2. Application Server using Amazon Web Services. This portion explains how to interact with Braintree’s server in a secure manner.
3. Initial Version Using Vanilla-JavaScript discusses building an application that can receive payments.
4. React Component Based Version is about putting React inside a React Native application.
Introduction
In part 3 of this series, I presented design and implementation of an application that displayed a Braintree payment UI to the user and allowed them to enter their credit card information to make a purchase. The implementation was done completely in JavaScript. This time I will use React to create a webpage containing the payment UI.
Design
The biggest difference between this design and the one shown in the previous article is the use of React to create the HTML and JavaScript that is presented in the <WebView/>
component.
Instead of using webpack to package and bundle JavaScript, I used it to package and bundle React JSX. This involved the typical React pattern of creating an HTML file with a <div>
element that serves as the “target” to place the compiled React JSX into. This creates a bundle.js file which is compiled into an index.html file which is then imported by the React <WebView/>
component for rendering.
So, one may ask, why go through the trouble of even using React inside a React Native webview.
For one, I did it because I thought that taking advantage of the reactive nature of React in both the React and React Native portions of my project would lead to cleaner, understandable, and more maintainable code; some of the primary reasons for using React in the first place. Additionally, it meant that I could follow the same pattern for creating both components. Since this version of the project uses react-native-webview-messaging just like the previous version, I could set up listeners and fire messages same way both the React and React Native sides.
This change represents the most significant differences between this and previous versions of this article.
Implementation
Since I’m assuming that you’ve read my previous article in this series, I will be focusing on the React code and packaging it for use by react-native-webview-messaging.
Once again, I relied on webpack to convert the JSX into HTML that my <WebView>
could use as it’s source prop.
Again, it’s very similar to my previous version. The most import part is line 29 which tells babel to transpile any JSX it finds into JS. Line 6 tells babel to begin working in the braintreeReact.js file which contains the React code, and line 41 tells babel which html file to combine with braintreeReact.js to create the final index.js that will be imported by the react-native-messaging-webview.
Next, I’ll walk through the code in braintreeReact.js
. Don’t worry if it seems like a lot of code. For one thing, I like white-space. Additionally, I’ll go though the important parts line by line below.
On lines 3 and 4 I manually import a downloaded version of React. I encountered errors attempting to use the version of React in my node modules directory. I attributed this to version conflicts due to using Expo, which has it’s own specific React dependencies.
Line 8 imports glamorous which I used for styling in lines 12 to 36.
The PrintData
function on line 40 is used for debugging. Debugging a <WebView/>
can be difficult since you can’t rely on console logs and breakpoints. To get around this, the PrintData
function prints passed objects and strings to a <div>
element in the index.html
.
Line 52 is where the actual BraintreeHTML component starts. It initially has one state variable, currentPaymentStatus
which is used to conditionally render feedback to the user throughout the payment process.
The componentDidMount
function provides an opportunity to register listeners for interaction with the parent component.
The createCreditCardUI
function does exactly the same thing as before. It places the Braintree UI inside of a <div>
element on the index.html. It then saves the Braintree instance
object in the component’s state for later use.
Next, the handler handleSubmitPurchaseButtonClicked
function does exactly what it’s name suggests. It is fired once the user clicks the button that submits purchase information, at which point it sets the currentPayementStatus
state variable to “PAYMENT_PENDING” and emits a “RETRIEVE_NONCE_PENDING” message to the parent so that it can display an <ActivityIndicator/>
component. It then requests a nonce using the Braintree API’s requestPaymentMethod
of and submits either a message indicating success or failure to the parent component.
Several things are happening inside the render function. First, the components created with glamorous are used to format individual elements. More importantly, renderIf
from the render-if library is used to conditionally render either the payment UI, a message thanking the user for their purchase, or a message informing the user that their was a problem with their payment. The value of the component state variable currentPaymentStatus
determines which of the three are rendered.
Conclusion
This post shows that it is possible to use React to create the content of a React Native <WebView/>
. It also demonstrated a method to communicate between the <WebView/>
and the HTML created by the React. Additionally, it demonstrated a technique to show useful debugging information from the HTML which itself has no access to the console or the debugger.