Mithunkumar
Mithunkumar

Reputation: 231

React js Stripe checkout is not working

I am trying to render a stripe checkout default form in React js application.

<form action="/your-server-side-code" method="POST">
  <script
    src="https://checkout.stripe.com/checkout.js" className="stripe-button"
    data-key="pk_test_oDALA0jNyxDzbRz5RstV4qOr"
    data-amount="999"
    data-name="test"
    data-description="Widget"
    data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
    data-locale="auto">
  </script>
</form>

Its not displaying anything and not getting error also. How do i get that pay button and form.

Upvotes: 12

Views: 5225

Answers (2)

adamcee
adamcee

Reputation: 81

Chris's answer was excellent, however I had to make a few minor changes in order for the code to function. I've also removed the TypeScript function types (for those of us not using TypeScript). Comments are added where changes to the answer have been made. FYI this is my first post, please let me know if this should be a Comment instead of an Answer.

export default class Cards extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            loading: true,
            stripeLoading: true,
        };
        // onStripeUpdate must be bound or else clicking on button will produce error.
        this.onStripeUpdate = this.onStripeUpdate.bind(this);
        // binding loadStripe as a best practice, not doing so does not seem to cause error.
        this.loadStripe = this.loadStripe.bind(this);
    }

    loadStripe(onload) {
        if(! window.StripeCheckout) {
            const script = document.createElement('script');
            script.onload = function () {
                console.info("Stripe script loaded");
                onload();
            };
            script.src = 'https://checkout.stripe.com/checkout.js';
            document.head.appendChild(script);
        } else {
            onload();
        }
    }

    componentDidMount() {

        this.loadStripe(() => {
            this.stripeHandler = window.StripeCheckout.configure({
                key: 'pk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
                image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
                locale: 'auto',
                token: (token) => {
                    this.setState({ loading: true });
                    // use fetch or some other AJAX library here if you dont want to use axios
                    axios.post('/your-server-side-code', {
                        stripeToken: token.id,
                    });
                }
            });

            this.setState({
                stripeLoading: false,
                // loading needs to be explicitly set false so component will render in 'loaded' state.
                loading: false,
            });
        });
    }

    componentWillUnmount() {
        if(this.stripeHandler) {
            this.stripeHandler.close();
        }
    }

    onStripeUpdate(e) {
        this.stripeHandler.open({
            name: 'test',
            description: 'widget',
            panelLabel: 'Update Credit Card',
            allowRememberMe: false,
        });
        e.preventDefault();
    }

    render() {
        const { stripeLoading, loading } = this.state;
        return (
            <div>
                {(loading || stripeLoading)
                    ? <p>loading..</p>
                    : <button onClick={this.onStripeUpdate}>Add CC</button>
                }
            </div>
        );
    }
}

Upvotes: 8

Chris
Chris

Reputation: 58312

The main issue you are probably having is loading a script within React.

One approach is to load the checkout script only when needed (assuming some form of spa), then just directly call it. This is akin to the "custom" version on the documentation page: https://stripe.com/docs/checkout#integration-custom

If you are already loading checkout.js (for example before your "app.js"), then the below can be simplified a bit by not manually loading in the script.

import React from 'react';

export default class Cards extends React.Component {

    constructor(props:Object) {
        super(props);
        this.state = {
            loading: true,
            stripeLoading: true,
        };
    }

    loadStripe(onload:Function) {
        if(! window.StripeCheckout) {
            const script = document.createElement('script');
            script.onload = function () {
                console.info("Stripe script loaded");
                onload();
            };
            script.src = 'https://checkout.stripe.com/checkout.js';
            document.head.appendChild(script);
        } else {
            onload();
        }
    }

    componentDidMount() {

        this.loadStripe(() => {
            this.stripehandler = window.StripeCheckout.configure({
                key: 'pk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
                image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
                locale: 'auto',
                token: (token) => {
                    this.setState({ loading: true });
                    axios.post('/your-server-side-code', {
                        stripeToken: token.id,
                    });
                }
            });

            this.setState({
                stripeLoading: false
            });
        });
    }

    componentWillUnmount() {
        if(this.stripehandler) {
            this.stripehandler.close();
        }
    }

    onStripeUpdate(e:Object) {
        this.stripehandler.open({
            name: 'test',
            description: 'widget',
            panelLabel: 'Update Credit Card',
            allowRememberMe: false,
        });
        e.preventDefault();
    }

    render() {
        const { stripeLoading, loading } = this.state;
        return (
            <div>
                {(loading || stripeLoading)
                    ? <p>loading..</p>
                    : <button onClick={this.onStripeUpdate}>Add CC</button>
                }
            </div>
        );
    }
}

Upvotes: 11

Related Questions