7

I am using react-stripe-elements to create a token for payments. However, according to the documentation when the card form is wrapped in the Elements component it should automatically pickup which stripe elements to tokenize.

However, in this case we are presented with the error

You must provide a Stripe Element or a valid token type to create a Token.

Here is the code:

import React from 'react';
import {CardCVCElement, CardExpiryElement, CardNumberElement, PostalCodeElement, StripeProvider, Elements} from 'react-stripe-elements';

class CheckoutForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(ev) {
    ev.preventDefault();

    this.props.stripe.createToken({email: 'test@test.com'}).then(({token }) => {console.log('Received Stripe token:', token)});
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Card details
          <CardNumberElement />
          <CardExpiryElement />
          <CardCVCElement />
          <PostalCodeElement />
        </label>
        <button>Confirm order</button>
      </form>
    );
  }
}


class App extends React.Component {
  constructor() {
    super();
    this.state = { stripe: null };
  }

  componentDidMount() {
    this.setState({ stripe: window.Stripe('test_key') });
  }

  render() {
    return (
      <StripeProvider stripe={this.state.stripe}>
        <Elements>
          <CheckoutForm stripe={this.state.stripe} />
        </Elements>
      </StripeProvider>
    );
  }
}

export default App;

According to the documentation the following should be true:

'Within the context of Elements, this call to createToken knows which Element to tokenize, since there's only one in this group.'

However, this doesn't seem to be the case. I have also tried using the single 'Card Element' and have not found any success in doing so.

4

4 回答 4

4

在评论中,他们正确地说您需要使用 HOC injectStripe

提到您需要传递要从中标记数据的元素的文档stripe.createToken

同样来自github repo README

⚠️ 注意 injectStripe 不能用在渲染 Elements 组件的同一个元素上;它必须用于 Elements 的子组件。injectStripe 返回一个包装的组件,该组件需要位于您想要访问 this.props.stripe 的任何代码之下但之上。

在我的特定情况下,我使用的是 Mobx 商店,我需要createToken在同一个地方处理和提交表单。即使我在初始化后引用了条带,它也不起作用。createToken调用需要来自 Elements 的子组件并注入条带。

我最终有:

@inject('signupStore')
@observer
class CardInput extends React.Component {
componentDidMount() {
    const { signupStore } = this.props;
    const handleCard = async name => {
        return await this.props.stripe.createToken({ name: name });
    };
    signupStore.assignHandleCard(handleCard);
}

render() {
    return (
        <label>
            Card details
            <CardElement style={{ base: { fontSize: '18px' } }} />
        </label>
    );
 }
}

export default injectStripe(CardInput);

将处理程序传回商店,然后从那里使用它。

部分signupStore

@action
async submitForm(formValues) {
    if (this.stripe && this.handleCard) {
        const tokenResponse = await this.handleCard(
            `${formValues.firstName} ${formValues.lastName}`
        );

        runInAction(() => {
            console.log('Card token received ', tokenResponse);
            if (tokenResponse) {
                this.cardToken = tokenResponse.token.id;
                formValues.cardToken = this.cardToken;
            }
        });

        const response = await request.signup.submit(formValues);

        return response;
    }
    return null;
}
于 2018-08-22T14:01:29.573 回答
4

事实证明,我从来没有设法使用 react-stripe-elements 解决这个问题。我结束了使用标准 JS 版本(来自 stripe 文档)。这是我目前的工作解决方案:

import React from 'react';

class CheckoutForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);

    this.state = {
      elements: null,
      card: null
    };
  }

  componentWillReceiveProps() {
    this.setState({ elements: this.props.stripe.elements() }, () => {
      this.setState({ card: this.state.elements.create('card') }, () => {
        this.state.card.mount('#card-element');
      });
    });
  }

  handleSubmit(ev) {
    ev.preventDefault();
    this.props.stripe.createToken(this.state.card).then((token) => {
      console.log('Received Stripe token:', token);
    });
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <div className="row">
          <label >
            Credit or debit card
          </label>
          <div id="card-element"/>
          <div id="card-errors" role="alert"/>
        </div>
        <button>Submit Payment</button>
      </form>
    );
  }
}

class App extends React.Component {
  constructor() {
    super();
    this.state = {stripe: window.Stripe('test_key')};
  }

  render() {
    return (
      <CheckoutForm stripe={this.state.stripe}/>
    );
  }
}

export default App;
于 2018-01-30T16:13:19.447 回答
1

React js 它为我工作卡组件,获取错误,卡详细信息和生成令牌

import React, { useState, useEffect } from "react";
import {loadStripe} from '@stripe/stripe-js';
import {CardElement,Elements,useStripe,useElements} from '@stripe/react-stripe-js';
const stripePromise = loadStripe('pk_test_YOUR_STRIPE_KYE');
const CheckoutForm = () => {
const stripe = useStripe();
const elements = useElements();

const handleSubmit = async (event) => {
  event.preventDefault();
  const {error, paymentMethod} = await stripe.createPaymentMethod({
    type: 'card',
    card: elements.getElement(CardElement),
  });
    console.log("paymentMethod",paymentMethod);  
    console.log("error", error);
    if (paymentMethod) {
            const cardElement = elements.getElement(CardElement);
            let token  = await stripe.createToken(cardElement);
            console.log(token);
    }
};

return (
     
    <div>
    <form onSubmit={ handleSubmit }>
     <div className="login-box" id="step2"  >

              
             <div className="form-row">
                  <label for="card-element" style={ { color:" #76bbdf" } }>
                      Credit or debit card
                  </label>
              </div>
              
                  <div  >
                      <CardElement
                          className="StripeElement"
                            options={{
                                style: {
                                base: {
                                    fontSize: '16px',
                                    color: '#424770',
                                    '::placeholder': {
                                    color: '#aab7c4',
                                    },
                                },
                                invalid: {
                                    color: '#9e2146',
                                },
                                },
                            }}
                      />
                    </div>
                    <button name="submintbtn2" className="btn btn-primary"  > SUBSCRIBE </button>
                </div>
                </form>
    </div>
)};
const Registration = () => (
<div>
<Elements stripe={stripePromise}>
  <CheckoutForm />
    </Elements>
    </div>
); 
export default Registration;
于 2021-03-24T17:14:16.703 回答
1

有了新的@stripe/react-stripe-js库,它有点不同。我们需要使用ElementsConsumer组件。使用loadStripe方法加载条带,并使用Elements组件将您的表单与 Stripe 一起使用。

这是一个基本的例子。

import { Elements, loadStripe } from "@stripe/react-stripe-js"

const stripePromise = loadStripe(STRIPEKEY)

<Elements stripe={stripePromise}>
   <CardForm />
</Elements>

CardForm.js

import {
  CardNumberElement,
  CardExpiryElement,
  CardCvcElement,
  ElementsConsumer,
} from "@stripe/react-stripe-js"

const StripeForm = ({ stripe, elements }) => {

  const handleSubmit = async () => {
    if (!stripe || !elements) {
      return
    }
    const cardNumberElement = elements.getElement(CardNumberElement)
    const res = await stripe.createToken(cardNumberElement)
  }

  return (
      <form>
        <div>
          <label htmlFor="cardNumber">Card Number</label>
          <div>
            <CardNumberElement />
          </div>
        </div>
        <div>
          <label htmlFor="cardName">Card Name</label>
          <input
            type="text"
            name="cardName"
            required
            placeholder="Please Enter"
            pattern="[A-Za-z]"
          />
        </div>
        <div>
          <label htmlFor="expDate">Exp. Date</label>
          <div>
            <CardExpiryElement />
          </div>
        </div>
        <div>
          <label htmlFor="CVC">CVC</label>
          <div>
            <CardCvcElement />
          </div>
        </div>
      </form>
  )
}

const CardForm = () => {
  return (
    <ElementsConsumer>
      {({ stripe, elements }) => (
        <StripeForm stripe={stripe} elements={elements} />
      )}
    </ElementsConsumer>
  )
}

export default CardForm
于 2021-04-26T07:51:52.117 回答