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()
系统:
- 反应 16.11.0
- Strapi 3.0.0-beta.17.5
- 条纹:7.13.0
目标: 当点击模式上的提交时,条纹应该起作用。根据 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()。
系统:
- 反应 16.11.0
- Strapi 3.0.0-beta.17.5
- 条纹:7.13.0
目标: 当点击模式上的提交时,条纹应该起作用。根据 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()。