admin管理员组

文章数量:1415145

WebpackError: Could not find Elements context; You need to wrap the part of your app that calls useStripe() in an provider

I am using stripe to collect donations for a gatsby website I am developing. It uses firebase as the backend. I'm successfully accepting donations with stripe locally. But get a webpack error when I push to github so my changes will be on my live netlify link. Here is a part of the error message:

5:05:22 PM: success run queries - 80.938s - 42/42 0.52/s
5:05:30 PM: []
5:05:30 PM: failed Building static HTML for pages - 4.832s
5:05:30 PM: error Building static HTML failed for path "/contactDonate/"
5:05:30 PM:   197 | var parseElementsContext = function parseElementsContext(ctx, useCase) {
5:05:30 PM:   198 |   if (!ctx) {
5:05:30 PM: > 199 |     throw new Error("Could not find Elements context; You need to wrap the part of your app that ".concat(useCase, " in an <Elements> provider."));
5:05:30 PM:       | ^
5:05:30 PM:   200 |   }
5:05:30 PM:   201 |
5:05:30 PM:   202 |   return ctx;
5:05:30 PM: 
5:05:30 PM:   WebpackError: Could not find Elements context; You need to wrap the part of yo  ur app that calls useStripe() in an <Elements> provider.
5:05:30 PM:   
5:05:30 PM:   - react-stripe.esm.js:199 parseElementsContext
5:05:30 PM:     node_modules/@stripe/react-stripe-js/dist/react-stripe.esm.js:199:1
5:05:30 PM:   
5:05:30 PM:   - react-stripe.esm.js:302 useElementsContextWithUseCase
5:05:30 PM:     node_modules/@stripe/react-stripe-js/dist/react-stripe.esm.js:302:1
5:05:30 PM:   
5:05:30 PM:   - react-stripe.esm.js:319 useStripe
5:05:30 PM:     node_modules/@stripe/react-stripe-js/dist/react-stripe.esm.js:319:1
5:05:30 PM:   
5:05:30 PM:   - contactDonate.js:45 ContactDonate
5:05:30 PM:     src/pages/contactDonate.js:45:27
5:05:30 PM:   
5:05:30 PM: 

The error seems to be with how I loadStripe. I call loadStripe with my stripe public key in my Layout ponent because that gets rendered on every page and I follow the instructions from this documentation provided by stripe. Stripe Docs

I've also tried making an async call to it because I saw that on the documentation here. But even that doesn't seem to work. In addition I went to my ContactDonate page where I use the stripe ponents and used loadStripe there but that gave me an error. It seemed redundant to load stripe again on my ContactPage when I already do it in my Layout ponent.Stripe Docs async

The whole app works locally (with or without an async call to loadStripe) so I assumed I was loading stripe correctly. Let me know if I can provide any other details about my project.

I even tried changing the stripe key from test to live. That doesn't work either.

The layout implementation below uses async to loadStripe. Prior to this I only had the the following line.

const stripePromise = loadStripe('STRIPE_SECRET_KEY'); 

Layout.js

/**
 * Layout ponent that queries for data
 * with Gatsby's useStaticQuery ponent
 *
 * See: /
 */

import React, { useState, useEffect } from 'react';
import styled from 'styled-ponents';
import PropTypes from 'prop-types';
import { useStaticQuery, graphql } from 'gatsby';
import { FirebaseContext, useAuth } from '../Firebase';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';

import Header from '../Header/header';
import SideMenu from './sideMenu';
import Backdrop from './backdrop';
import Footer from '../Footer/footer';

/**
 * todo frontend: add close sideMenu & backdrop upon navigation from sideMenu link
 * todo frontend: fix the extra spacing to the right of website in mobile view
 * todo frontend: store stripe key as env variable
 * todo frontend: change api key from test to production
 */
let stripePromise;
const loadStripePromise = async () => {
  stripePromise = await loadStripe('STRIPE_SECRET_KEY');
};
loadStripePromise();

const LayoutContainer = styled.div`
  width: 100%;
  height: 100%;
`;

const Layout = ({ children }) => {
  const { user, firebase, loading } = useAuth();
  const [sideMenuIsOpen, setSideMenuIsOpen] = useState(false);
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `);

  // handle menu toggled event
  // invert value of state
  function menuToggleClickHandler() {
    setSideMenuIsOpen(!sideMenuIsOpen);
  }

  function backdropClickHandler() {
    setSideMenuIsOpen(false);
  }

  if (stripePromise) {
    console.log('stripe promise loaded');
  } else {
    console.log('stripe promises NOT loaded');
  }

  return (
    <FirebaseContext.Provider value={{ user, firebase, loading }}>
      <Elements stripe={stripePromise}>
        <Header
          siteTitle={data.site.siteMetadata.title}
          menuClickHandler={menuToggleClickHandler}
        />
        <SideMenu show={sideMenuIsOpen} />
        {sideMenuIsOpen === true ? (
          <Backdrop click={backdropClickHandler} />
        ) : null}
        <LayoutContainer>
          <main>{children}</main>
          <Footer />
        </LayoutContainer>
      </Elements>
    </FirebaseContext.Provider>
  );
};

Layout.propTypes = {
  children: PropTypes.node.isRequired,
};

export default Layout;

package.json

{
  "name": "gatsby-starter-default",
  "private": true,
  "description": "A simple starter to get up and developing quickly with Gatsby",
  "version": "0.1.0",
  "author": "SasheemDev <[email protected]>",
  "dependencies": {
    "@stripe/react-stripe-js": "^1.1.2",
    "@stripe/stripe-js": "^1.3.1",
    "axios": "^0.19.2",
    "firebase": "^7.8.2",
    "gatsby": "^2.19.7",
    "gatsby-background-image": "^0.10.2",
    "gatsby-firesource": "^2.0.3",
    "gatsby-image": "^2.2.39",
    "gatsby-plugin-google-fonts": "^1.0.1",
    "gatsby-plugin-manifest": "^2.2.39",
    "gatsby-plugin-offline": "^3.0.32",
    "gatsby-plugin-react-helmet": "^3.1.21",
    "gatsby-plugin-react-svg": "^3.0.0",
    "gatsby-plugin-remote-images": "^2.1.0",
    "gatsby-plugin-sass": "^2.1.28",
    "gatsby-plugin-sharp": "^2.4.3",
    "gatsby-plugin-smoothscroll": "^1.1.0",
    "gatsby-source-filesystem": "^2.1.46",
    "gatsby-transformer-sharp": "^2.3.13",
    "moment": "^2.24.0",
    "node-sass": "^4.13.1",
    "prop-types": "^15.7.2",
    "react": "^16.12.0",
    "react-date-picker": "^8.0.0",
    "react-dom": "^16.12.0",
    "react-helmet": "^5.2.1",
    "react-tabs": "^3.1.0",
    "styled-ponents": "^5.0.1"
  },
  "devDependencies": {
    "prettier": "^1.19.1"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write \"**/*.{js,jsx,json,md}\"",
    "start": "npm run develop",
    "serve": "gatsby serve",
    "clean": "gatsby clean",
    "test": "echo \"Write tests! -> /unit-testing\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": ""
  },
  "bugs": {
    "url": ""
  }
}

gatsby-browser.js/gatsby-ssr.js

const stripePromise = loadStripe('pk_test_kfC9T');

export const wrapPageElement = ({ element, props }) => {
  return (
    <Elements stripe={stripePromise}>
      <Layout {...props}>{element}</Layout>
    </Elements>
  );
};

WebpackError: Could not find Elements context; You need to wrap the part of your app that calls useStripe() in an provider

I am using stripe to collect donations for a gatsby website I am developing. It uses firebase as the backend. I'm successfully accepting donations with stripe locally. But get a webpack error when I push to github so my changes will be on my live netlify link. Here is a part of the error message:

5:05:22 PM: success run queries - 80.938s - 42/42 0.52/s
5:05:30 PM: []
5:05:30 PM: failed Building static HTML for pages - 4.832s
5:05:30 PM: error Building static HTML failed for path "/contactDonate/"
5:05:30 PM:   197 | var parseElementsContext = function parseElementsContext(ctx, useCase) {
5:05:30 PM:   198 |   if (!ctx) {
5:05:30 PM: > 199 |     throw new Error("Could not find Elements context; You need to wrap the part of your app that ".concat(useCase, " in an <Elements> provider."));
5:05:30 PM:       | ^
5:05:30 PM:   200 |   }
5:05:30 PM:   201 |
5:05:30 PM:   202 |   return ctx;
5:05:30 PM: 
5:05:30 PM:   WebpackError: Could not find Elements context; You need to wrap the part of yo  ur app that calls useStripe() in an <Elements> provider.
5:05:30 PM:   
5:05:30 PM:   - react-stripe.esm.js:199 parseElementsContext
5:05:30 PM:     node_modules/@stripe/react-stripe-js/dist/react-stripe.esm.js:199:1
5:05:30 PM:   
5:05:30 PM:   - react-stripe.esm.js:302 useElementsContextWithUseCase
5:05:30 PM:     node_modules/@stripe/react-stripe-js/dist/react-stripe.esm.js:302:1
5:05:30 PM:   
5:05:30 PM:   - react-stripe.esm.js:319 useStripe
5:05:30 PM:     node_modules/@stripe/react-stripe-js/dist/react-stripe.esm.js:319:1
5:05:30 PM:   
5:05:30 PM:   - contactDonate.js:45 ContactDonate
5:05:30 PM:     src/pages/contactDonate.js:45:27
5:05:30 PM:   
5:05:30 PM: 

The error seems to be with how I loadStripe. I call loadStripe with my stripe public key in my Layout ponent because that gets rendered on every page and I follow the instructions from this documentation provided by stripe. Stripe Docs

I've also tried making an async call to it because I saw that on the documentation here. But even that doesn't seem to work. In addition I went to my ContactDonate page where I use the stripe ponents and used loadStripe there but that gave me an error. It seemed redundant to load stripe again on my ContactPage when I already do it in my Layout ponent.Stripe Docs async

The whole app works locally (with or without an async call to loadStripe) so I assumed I was loading stripe correctly. Let me know if I can provide any other details about my project.

I even tried changing the stripe key from test to live. That doesn't work either.

The layout implementation below uses async to loadStripe. Prior to this I only had the the following line.

const stripePromise = loadStripe('STRIPE_SECRET_KEY'); 

Layout.js

/**
 * Layout ponent that queries for data
 * with Gatsby's useStaticQuery ponent
 *
 * See: https://www.gatsbyjs/docs/use-static-query/
 */

import React, { useState, useEffect } from 'react';
import styled from 'styled-ponents';
import PropTypes from 'prop-types';
import { useStaticQuery, graphql } from 'gatsby';
import { FirebaseContext, useAuth } from '../Firebase';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';

import Header from '../Header/header';
import SideMenu from './sideMenu';
import Backdrop from './backdrop';
import Footer from '../Footer/footer';

/**
 * todo frontend: add close sideMenu & backdrop upon navigation from sideMenu link
 * todo frontend: fix the extra spacing to the right of website in mobile view
 * todo frontend: store stripe key as env variable
 * todo frontend: change api key from test to production
 */
let stripePromise;
const loadStripePromise = async () => {
  stripePromise = await loadStripe('STRIPE_SECRET_KEY');
};
loadStripePromise();

const LayoutContainer = styled.div`
  width: 100%;
  height: 100%;
`;

const Layout = ({ children }) => {
  const { user, firebase, loading } = useAuth();
  const [sideMenuIsOpen, setSideMenuIsOpen] = useState(false);
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `);

  // handle menu toggled event
  // invert value of state
  function menuToggleClickHandler() {
    setSideMenuIsOpen(!sideMenuIsOpen);
  }

  function backdropClickHandler() {
    setSideMenuIsOpen(false);
  }

  if (stripePromise) {
    console.log('stripe promise loaded');
  } else {
    console.log('stripe promises NOT loaded');
  }

  return (
    <FirebaseContext.Provider value={{ user, firebase, loading }}>
      <Elements stripe={stripePromise}>
        <Header
          siteTitle={data.site.siteMetadata.title}
          menuClickHandler={menuToggleClickHandler}
        />
        <SideMenu show={sideMenuIsOpen} />
        {sideMenuIsOpen === true ? (
          <Backdrop click={backdropClickHandler} />
        ) : null}
        <LayoutContainer>
          <main>{children}</main>
          <Footer />
        </LayoutContainer>
      </Elements>
    </FirebaseContext.Provider>
  );
};

Layout.propTypes = {
  children: PropTypes.node.isRequired,
};

export default Layout;

package.json

{
  "name": "gatsby-starter-default",
  "private": true,
  "description": "A simple starter to get up and developing quickly with Gatsby",
  "version": "0.1.0",
  "author": "SasheemDev <[email protected]>",
  "dependencies": {
    "@stripe/react-stripe-js": "^1.1.2",
    "@stripe/stripe-js": "^1.3.1",
    "axios": "^0.19.2",
    "firebase": "^7.8.2",
    "gatsby": "^2.19.7",
    "gatsby-background-image": "^0.10.2",
    "gatsby-firesource": "^2.0.3",
    "gatsby-image": "^2.2.39",
    "gatsby-plugin-google-fonts": "^1.0.1",
    "gatsby-plugin-manifest": "^2.2.39",
    "gatsby-plugin-offline": "^3.0.32",
    "gatsby-plugin-react-helmet": "^3.1.21",
    "gatsby-plugin-react-svg": "^3.0.0",
    "gatsby-plugin-remote-images": "^2.1.0",
    "gatsby-plugin-sass": "^2.1.28",
    "gatsby-plugin-sharp": "^2.4.3",
    "gatsby-plugin-smoothscroll": "^1.1.0",
    "gatsby-source-filesystem": "^2.1.46",
    "gatsby-transformer-sharp": "^2.3.13",
    "moment": "^2.24.0",
    "node-sass": "^4.13.1",
    "prop-types": "^15.7.2",
    "react": "^16.12.0",
    "react-date-picker": "^8.0.0",
    "react-dom": "^16.12.0",
    "react-helmet": "^5.2.1",
    "react-tabs": "^3.1.0",
    "styled-ponents": "^5.0.1"
  },
  "devDependencies": {
    "prettier": "^1.19.1"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write \"**/*.{js,jsx,json,md}\"",
    "start": "npm run develop",
    "serve": "gatsby serve",
    "clean": "gatsby clean",
    "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github./gatsbyjs/gatsby-starter-default"
  },
  "bugs": {
    "url": "https://github./gatsbyjs/gatsby/issues"
  }
}

gatsby-browser.js/gatsby-ssr.js

const stripePromise = loadStripe('pk_test_kfC9T');

export const wrapPageElement = ({ element, props }) => {
  return (
    <Elements stripe={stripePromise}>
      <Layout {...props}>{element}</Layout>
    </Elements>
  );
};
Share Improve this question edited Apr 14, 2020 at 21:50 Sasheem asked Apr 14, 2020 at 18:05 SasheemSasheem 1313 silver badges12 bronze badges 0
Add a ment  | 

1 Answer 1

Reset to default 7

This is likely due to the way the Elements Provider ponent is set up which has to be done a bit differently in Gatsby. More on that here:

https://www.gatsbyjs/blog/2019-01-31-using-react-context-api-with-gatsby/

The fix would be to export a wrapRootElement function [0] from the gatsby-browser.js file in the root of your project. The Gatsby CLI creates this file by default, but if for whatever reason it's not there you will need to add it.

Within gatsby-browser.js include Stripe as follows:

import React from "react"

import { loadStripe } from '@stripe/stripe-js';
import { Elements } from '@stripe/react-stripe-js';

const stripePromise = loadStripe('pk_test_xyz');

export const wrapRootElement = ({ element }) => {
  return (
    <Elements stripe={stripePromise}>
      {element} 
    </Elements>      
  )
}

Be sure to replace pk_test_xyz with your own publishable key: https://dashboard.stripe./test/apikeys

Once that's in place you can remove the Stripe-related code from your Layout.js ponent.

That should do it!

[0] https://www.gatsbyjs/docs/browser-apis/#wrapRootElement

本文标签: