Skip to content
This repository has been archived by the owner on Mar 27, 2021. It is now read-only.

Commit

Permalink
Merge pull request #458 from stripe/dweedon/inject-elements
Browse files Browse the repository at this point in the history
inject elements
  • Loading branch information
dweedon-stripe authored Nov 13, 2019
2 parents 93e50bc + 9580eea commit 91c465c
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 132 deletions.
45 changes: 43 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,44 @@
`react-stripe-elements` adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## v6.0.0 - 2019-11-05

### New Features

- `injectStripe` now injects a reference to the Elements instance created by
`<Elements>` as the prop `elements`.

The primary reason you would want an Elements instance is to use
[`elements.getElement()`](https://stripe.com/docs/stripe-js/reference#elements-get-element).
which provides an easy way to get a reference to an Element. You will need to
get a refrence to an Element to use
[`confirmCardPayment`](https://stripe.com/docs/stripe-js/reference#stripe-confirm-card-payment),
[`confirmCardSetup()`](https://stripe.com/docs/stripe-js/reference#stripe-confirm-card-setup),
or
[`createPaymentMethod()`](https://stripe.com/docs/stripe-js/reference#stripe-create-payment-method).

Note that the old API for `createPaymentMethod` will continue to work and
provide automatic element injection, but we are updating documentation and
examples to use the new argument shape:

```js
// old shape with automatic element detection - still works
this.props.stripe.createPaymentMethod('card').then(/* ... */);

// new shape without automatic element detection - recommended and will work with new non-card PaymentMethods
this.props.stripe
.createPaymentMethod({
type: 'card',
card: this.props.elements.getElement('card'),
})
.then(/* ... */);
```

### Breaking Changes

- We have removed the `getElement` method on RSE components that we introduced
in v5.1.0 in favor of the above change. Sorry for the churn.

## v5.1.0 - 2019-10-22

### New Features
Expand Down Expand Up @@ -53,9 +91,11 @@
): Promise<{error?: Object, setupIntent?: Object}>
```

For more information, please review the Stripe Docs:
````

For more information, please review the Stripe Docs:

- [`stripe.handleCardSetup`](https://stripe.com/docs/stripe-js/reference#stripe-handle-card-setup)
- [`stripe.handleCardSetup`](https://stripe.com/docs/stripe-js/reference#stripe-handle-card-setup)

### Deprecations

Expand Down Expand Up @@ -367,3 +407,4 @@ Initial release! Support for:
- CardExpiryElement
- CardCVCElement
- PostalCodeElement
````
144 changes: 65 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ styles, fonts).
- [Available components](#available-components)
- [Props shape](#props-shape-2)
- [Using `onReady`](#using-onready)
- [Using `getElement`](#using-getelement)
- [`injectStripe` HOC](#injectstripe-hoc)
- [Example](#example)
- [Troubleshooting](#troubleshooting)
Expand Down Expand Up @@ -167,19 +166,13 @@ Use the `injectStripe` [Higher-Order Component][hoc] (HOC) to build your payment
form components in the `Elements` tree. The [Higher-Order Component][hoc]
pattern in React can be unfamiliar to those who've never seen it before, so
consider reading up before continuing. The `injectStripe` HOC provides the
`this.props.stripe` property that manages your `Elements` groups. Within an
injected component, you can call any of the following:

- `this.props.stripe.createPaymentMethod`
- `this.props.stripe.createToken`
- `this.props.stripe.createSource`
- `this.props.stripe.handleCardPayment`
- `this.props.stripe.handleCardSetup`

Calling any of these methods will collect data from the appropriate Element and
use it to submit payment data to Stripe.
`this.props.stripe` and `this.props.elements` properties that manage your
`Elements` groups. Within an injected component, you can call any of the methods
on the [Stripe][stripe] or [Elements][elements] objects.

[hoc]: https://facebook.github.io/react/docs/higher-order-components.html
[stripe]: https://stripe.com/docs/stripe-js/reference#the-stripe-object
[elements]: https://stripe.com/docs/stripe-js/reference#the-elements-object

> :warning: NOTE `injectStripe` cannot be used on the same element that renders
> the `Elements` component; it must be used on the child component of
Expand All @@ -200,29 +193,49 @@ class CheckoutForm extends React.Component {
// We don't want to let default form submission happen here, which would refresh the page.
ev.preventDefault();

// Within the context of `Elements`, this call to createPaymentMethod knows from which Element to
// create the PaymentMethod, since there's only one in this group.
// Use Elements to get a reference to the Card Element mounted somewhere
// in your <Elements> tree. Elements will know how to find your Card Element
// becase only one is allowed.
// See our getElement documentation for more:
// https://stripe.com/docs/stripe-js/reference#elements-get-element
const cardElement = this.props.elements.getElement('card');

// From here we cal call createPaymentMethod to create a PaymentMethod
// See our createPaymentMethod documentation for more:
// https://stripe.com/docs/stripe-js/reference#stripe-create-payment-method
this.props.stripe
.createPaymentMethod('card', {billing_details: {name: 'Jenny Rosen'}})
.createPaymentMethod({
type: 'card',
card: cardElement,
billing_details: {name: 'Jenny Rosen'},
})
.then(({paymentMethod}) => {
console.log('Received Stripe PaymentMethod:', paymentMethod);
});

// You can also use handleCardPayment with the PaymentIntents API automatic confirmation flow.
// See our handleCardPayment documentation for more:
// https://stripe.com/docs/stripe-js/reference#stripe-handle-card-payment
this.props.stripe.handleCardPayment('{PAYMENT_INTENT_CLIENT_SECRET}', data);
// You can also use confirmCardPayment with the PaymentIntents API automatic confirmation flow.
// See our confirmCardPayment documentation for more:
// https://stripe.com/docs/stripe-js/reference#stripe-confirm-card-payment
this.props.stripe.confirmCardPayment('{PAYMENT_INTENT_CLIENT_SECRET}', {
payment_method: {
card: cardElement,
},
});

// You can also use handleCardSetup with the SetupIntents API.
// See our handleCardSetup documentation for more:
// https://stripe.com/docs/stripe-js/reference#stripe-handle-card-setup
this.props.stripe.handleCardSetup('{PAYMENT_INTENT_CLIENT_SECRET}', data);
// You can also use confirmCardSetup with the SetupIntents API.
// See our confirmCardSetup documentation for more:
// https://stripe.com/docs/stripe-js/reference#stripe-confirm-card-setup
this.props.stripe.confirmCardSetpu('{PAYMENT_INTENT_CLIENT_SECRET}', {
payment_method: {
card: cardElement,
},
});

// You can also use createToken to create tokens.
// See our tokens documentation for more:
// https://stripe.com/docs/stripe-js/reference#stripe-create-token
// With createToken, you will not need to pass in the reference to
// the Element. It will be inferred automatically.
this.props.stripe.createToken({type: 'card', name: 'Jenny Rosen'});
// token type can optionally be inferred if there is only one Element
// with which to create tokens
Expand All @@ -231,6 +244,8 @@ class CheckoutForm extends React.Component {
// You can also use createSource to create Sources.
// See our Sources documentation for more:
// https://stripe.com/docs/stripe-js/reference#stripe-create-source
// With createSource, you will not need to pass in the reference to
// the Element. It will be inferred automatically.
this.props.stripe.createSource({
type: 'card',
owner: {
Expand Down Expand Up @@ -640,45 +655,6 @@ export default CardSection;

[element]: https://stripe.com/docs/stripe-js/reference#other-methods

#### Using `getElement`

In addition to `onReady`, you can also access to the underlying Element by using
a [ref] to the access the component instance and calling `getElement()`.

Note that if you are async loading Stripe.js, until it loads `getElement` will
return `null`.

```jsx
// CardSection.js
import React from 'react';
import {CardElement} from 'react-stripe-elements';

class CardSection extends React.Component {
ref = React.createRef();

focus() {
const element = this.ref.current.getElement();

if (element) {
element.focus();
}
}

render = () => {
return (
<label>
Card details
<CardElement ref={this.ref} />
</label>
);
};
}

export default CardSection;
```

[ref]: https://reactjs.org/docs/refs-and-the-dom.html

### `injectStripe` HOC

```jsx
Expand All @@ -693,14 +669,13 @@ function injectStripe(
Use `injectStripe` to wrap a component that needs to interact with `Stripe.js`
to create sources or tokens.

1. First, create a component that accepts the `stripe` prop and calls
`this.props.stripe.createToken` or `this.props.stripe.createSource` when
necessary.
1. First, create a component that accepts the `stripe` prop and calls one of
the Stripe or Elements methods when necessary.
2. Wrap that component by passing it to `injectStripe` so that it actually
receives the `stripe` prop.
receives the `stripe` and `elements` props.
3. Render the component that `injectStripe` returns.

### Example
#### Example

```jsx
// 1. Create a component that uses this.props.stripe:
Expand All @@ -709,7 +684,12 @@ class CheckoutForm extends React.Component {
/* ... */
}
onCompleteCheckout() {
this.props.stripe.createPaymentMethod('card').then(/* ... */);
this.props.stripe
.createPaymentMethod({
type: 'card',
card: this.props.stripe.getElement('card'),
})
.then(/* ... */);
}
}

Expand Down Expand Up @@ -740,10 +720,16 @@ available with the `getWrappedInstance()` method of the wrapper component. This
feature can not be used if the wrapped component is a stateless function
component.

Within the wrapped component, the `stripe` prop has the type:
Within the wrapped component, the `stripe` and `elements` props have the type:

```jsx
type FactoryProps = {
elements: null | {
getElement: (type: string) => Element | null,
// For more detail and documentation on other methods available on
// the `elements` object, please refer to our official documentation:
// https://stripe.com/docs/elements/reference#the-elements-object
},
stripe: null | {
createToken: (tokenData: {type?: string}) => Promise<{
token?: Object,
Expand All @@ -754,36 +740,36 @@ type FactoryProps = {
error?: Object,
}>,
createPaymentMethod: (
type: string,
paymentMethodData?: Object
paymentMethodData: Object
) => Promise<{
paymentMethod?: Object,
error?: Object,
}>,
handleCardPayment: (
confirmCardPayment: (
clientSecret: string,
paymentMethodData?: Object
paymentIntentData?: Object
) => Promise<{
paymentIntent?: Object,
error?: Object,
}>,
handleCardSetup: (
confirmCardSetup: (
clientSecret: string,
paymentMethodData?: Object
paymentIntentData?: Object
) => Promise<{
setupIntent?: Object,
error?: Object,
}>,
// and other functions available on the `stripe` object,
// as officially documented here: https://stripe.com/docs/elements/reference#the-stripe-object
// For more detail and documentation on other methods available on
// the `stripe` object, please refer to our official documentation:
// https://stripe.com/docs/elements/reference#the-stripe-object
},
};
```

The `stripe` prop can only be `null` if you are using one of the
The `stripe` and `elements` props can only be `null` if you are using one of the
[Advanced integrations](#advanced-integrations) mentioned above, like loading
Stripe.js asynchronously or providing an existing instance. If you are using a
basic integration where you pass in an api key to `<StripeProvider/>`, it will
basic integration where you pass in an api key to `<StripeProvider/>`, they will
always be present.

## Troubleshooting
Expand Down
Loading

0 comments on commit 91c465c

Please sign in to comment.