title: Stripe checkout not working in my react + strapi app - getting "undefined" error with this.props.stripe.createToken()
body: <p>System:</p>
  
  <ul>
  <li>React 16.11.0 </li>
  <li>Strapi 3.0.0-beta.17.5 </li>
  <li>Stripe: 7.13.0</li>
  </ul>
  
  <p><strong>Goal:</strong> to when clicking on submit on the modal, the stripe should work. According to the documentation on stripe:
  <a href="https://stripe.com/docs/recipes/elements-react" rel="nofollow noreferrer">https://stripe.com/docs/recipes/elements-react</a>
  The injectStripe function wraps the component, creating a new component with an injected stripe prop, which contains a Stripe object. You must use the wrapped component in your application instead of the original CheckoutForm.</p>
  
  <p>So I assume that when I wrap it I can naturally access the stripe object within the CheckoutForm. </p>
  
  <p><strong>Error:</strong> can't read props of undefined</p>
  
  <p>Then I have another error:
  index.js:1375 Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().</p>
  
  <p>I have no idea what caused the above error. </p>
  
  <p><strong>Code:</strong> </p>
  
  <pre><code>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(()=&gt; {
          const items = getCart()
          setCartItems(items)
      }, [])
  
      const { address, zipcode, city, confirmEmail, toast, toastMsg, orderProcessing, modal } = formData
  
      const handleChange = ({event}) =&gt; {
          setFormData({...formData, [event.target.name]: event.target.value})
      }
  
      const showToast = (toastMsg, redirect = false) =&gt; {
          setFormData({...formData, toast: true, toastMsg})
          setTimeout(() =&gt; setFormData({...formData, toast: false, toastMsg:''},
          // if true passed to 'redirect' argument, redirect home
           ()=&gt; redirect &amp;&amp; history.push('/')), 
          5000)
      }
  
      const isFormEmpty = (address, zipcode, city, confirmEmail) =&gt; {
          return !address || !zipcode || !city || !confirmEmail
      }
  
      const closeModal = ( )=&gt; setFormData({...formData, modal: false})
  
      const handleConfirmOrder = event =&gt; {
          event.preventDefault()
           if (isFormEmpty(address, zipcode, city, confirmEmail)){
               showToast('Please fill in all the fields')
               return
           }
           setFormData({...formData, modal:true })
      }
  
      const handleSubmitOrder = async () =&gt; {
          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 (
          &lt;div&gt;
              some mark up code 
          &lt;/div&gt;
      )
  }
  
  const ConfirmationModal = ({ orderProcessing, cartItems, closeModal, handleSubmitOrder}) =&gt; (
      &lt;Modal
      accessibilityCloseLabel="close"
      accessibilityModalLabel="confirm your order"
      heading="Confirm Your Order"
      onDismiss={closeModal}
      footer={
          &lt;Box display="flex" marginRight={-1} marginLeft={-1} justifyContent="center"&gt;
              &lt;Box padding={1}&gt;
                  &lt;Button
                  size="lg"
                  color="blue"
                  text="Submit"
                  disabled={orderProcessing}
                  onClick={handleSubmitOrder}
                  /&gt;
              &lt;/Box&gt;
              &lt;Box padding={1}&gt;
                  &lt;Button
                  size="lg"
                  text="Cancel"
                  disabled={orderProcessing}
                  onClick={closeModal}
                  /&gt;
              &lt;/Box&gt;
          &lt;/Box&gt;
      }
      role="alertdialog"
      size="sm"
      &gt;
      {/* order summary */}
      {!orderProcessing &amp;&amp; (
          &lt;Box display="flex" justifyContent="center" alignItems="center" direction="column" padding={2} color="lightWash"&gt;
              {cartItems.map( item =&gt; (
                  &lt;Box key={item._id} padding={1}&gt;
                      &lt;Text size="lg" color="blue"&gt;
                      {item.name} x {item.quantity} - $ {item.quantity * item.price}
                      &lt;/Text&gt;
                  &lt;/Box&gt;
              ))}
              &lt;Box padding={2}&gt;
                  &lt;Text size="lg" color="blue" bold&gt;
                      Total: {calculatePrice(cartItems)}
                  &lt;/Text&gt;
              &lt;/Box&gt;
          &lt;/Box&gt;
      )}
          {/* order processing spinner */}
          &lt;Spinner show={orderProcessing} accessibilityLabel="Order Processing Spinner" /&gt;
          {orderProcessing &amp;&amp; &lt;Text align="center" italic&gt;Submitting your order...&lt;/Text&gt; }
      &lt;/Modal&gt;
  )
  
  const CheckoutForm = withRouter(injectStripe(_CheckoutForm))
  
  const Checkout = () =&gt; (
      &lt;StripeProvider apiKey="PUBLIC_KEY"&gt;
          &lt;Elements&gt;
              &lt;CheckoutForm /&gt;
          &lt;/Elements&gt;
      &lt;/StripeProvider&gt;
  )
  
  export default Checkout
  </code></pre>
  
  <p><strong>Question:</strong> why can't I access this.props.stripe.createToken() in the CheckoutForm? How could I fix it?</p>