Stripe checkout 在我的 react + strapi 应用程序中不起作用 - this.props.stripe.createToken() 出现 "undefined" 错误

Stripe checkout not working in my react + strapi app - getting "undefined" error with this.props.stripe.createToken()

系统:

目标: 当点击模式上的提交时,条纹应该起作用。根据 stripe 上的文档: https://stripe.com/docs/recipes/elements-react injectStripe 函数包装组件,创建一个带有注入 stripe prop 的新组件,其中包含一个 Stripe 对象。您必须在应用程序中使用包装组件,而不是原始的 CheckoutForm。

所以我假设当我包装它时我可以自然地访问 CheckoutForm 中的条带对象。

错误:无法读取未定义的属性

然后我有另一个错误: index.js:1375 警告:来自 useState() 和 useReducer() 挂钩的状态更新不支持第二个回调参数。要在渲染后执行副作用,请使用 useEffect() 在组件主体中声明它。

我不知道是什么导致了上述错误。

代码:

import React, {useState, useEffect, Fragment } from 'react'
import { Container, Box, Button, Heading, Text, TextField, Modal, Spinner} from 'gestalt'
import {Elements, StripeProvider, CardElement, injectStripe} from 'react-stripe-elements'
import axios from 'axios'
import { withRouter } from "react-router-dom"
import ToastMessage from './ToastMessage'
import { getCart, calculatePrice, clearCart, calculateAmount} from './utils'

const apiUrl = process.env.API_URL || 'http://localhost:1337/'


function _CheckoutForm ({ history}) {

    const [formData, setFormData] = useState({
        address: '',
        zipcode: '',
        city: '', 
        confirmEmail: '',
        toast: false,
        toastMsg: '',
        orderProcessing: false,
        modal: false
    })

    const [cartItems,setCartItems] = useState([])

    useEffect(()=> {
        const items = getCart()
        setCartItems(items)
    }, [])

    const { address, zipcode, city, confirmEmail, toast, toastMsg, orderProcessing, modal } = formData

    const handleChange = ({event}) => {
        setFormData({...formData, [event.target.name]: event.target.value})
    }

    const showToast = (toastMsg, redirect = false) => {
        setFormData({...formData, toast: true, toastMsg})
        setTimeout(() => setFormData({...formData, toast: false, toastMsg:''},
        // if true passed to 'redirect' argument, redirect home
         ()=> redirect && history.push('/')), 
        5000)
    }

    const isFormEmpty = (address, zipcode, city, confirmEmail) => {
        return !address || !zipcode || !city || !confirmEmail
    }

    const closeModal = ( )=> setFormData({...formData, modal: false})

    const handleConfirmOrder = event => {
        event.preventDefault()
         if (isFormEmpty(address, zipcode, city, confirmEmail)){
             showToast('Please fill in all the fields')
             return
         }
         setFormData({...formData, modal:true })
    }

    const handleSubmitOrder = async () => {
        const amount = calculateAmount(cartItems)
        setFormData({...formData, orderProcessing: true})
        let token
        try {
            //create stripe token
            //create order with strapi (request to backend)
            //set orderProcessing to false set modal to false
            //clear user cart 
            //show success toast

            const response = await this.props.stripe.createToken()
            token = response.token.id
            console.log(token)
            await axios
            .post(`${apiUrl}/orders`, {
                amount, 
                productItems: cartItems,
                city,
                zipcode, 
                address,
                token
            })
            setFormData({...formData, orderProcessing: false, modal: false})
            clearCart()
            showToast('Your order has been successfully submitted', true)
        } catch (error) {
            //set order processing to false, modal to false
            //show error message in toast
            setFormData({...formData, orderProcessing: false, modal: false})
            showToast(error.message)
        }
    }

    return (
        <div>
            some mark up code 
        </div>
    )
}

const ConfirmationModal = ({ orderProcessing, cartItems, closeModal, handleSubmitOrder}) => (
    <Modal
    accessibilityCloseLabel="close"
    accessibilityModalLabel="confirm your order"
    heading="Confirm Your Order"
    onDismiss={closeModal}
    footer={
        <Box display="flex" marginRight={-1} marginLeft={-1} justifyContent="center">
            <Box padding={1}>
                <Button
                size="lg"
                color="blue"
                text="Submit"
                disabled={orderProcessing}
                onClick={handleSubmitOrder}
                />
            </Box>
            <Box padding={1}>
                <Button
                size="lg"
                text="Cancel"
                disabled={orderProcessing}
                onClick={closeModal}
                />
            </Box>
        </Box>
    }
    role="alertdialog"
    size="sm"
    >
    {/* order summary */}
    {!orderProcessing && (
        <Box display="flex" justifyContent="center" alignItems="center" direction="column" padding={2} color="lightWash">
            {cartItems.map( item => (
                <Box key={item._id} padding={1}>
                    <Text size="lg" color="blue">
                    {item.name} x {item.quantity} - $ {item.quantity * item.price}
                    </Text>
                </Box>
            ))}
            <Box padding={2}>
                <Text size="lg" color="blue" bold>
                    Total: {calculatePrice(cartItems)}
                </Text>
            </Box>
        </Box>
    )}
        {/* order processing spinner */}
        <Spinner show={orderProcessing} accessibilityLabel="Order Processing Spinner" />
        {orderProcessing && <Text align="center" italic>Submitting your order...</Text> }
    </Modal>
)

const CheckoutForm = withRouter(injectStripe(_CheckoutForm))

const Checkout = () => (
    <StripeProvider apiKey="PUBLIC_KEY">
        <Elements>
            <CheckoutForm />
        </Elements>
    </StripeProvider>
)

export default Checkout

问题:为什么我无法在 CheckoutForm 中访问 this.props.stripe.createToken()?我该如何解决?

我终于想通了:我需要在函数_CheckoutForm中传递props,然后我就可以写props.history,或者props.stripe.createToken()。