我应该在前端的什么位置为我的 Gatsby 网站加载 Stripe?我对 Netlify 的推动因我当前的实施而崩溃
Where on the front end should I loadStripe for my Gatsby website? My push to Netlify crashes with my current implenation
WebpackError:找不到元素上下文;您需要将调用 useStripe() 的应用程序部分包装在提供程序中
我正在使用 stripe 为我正在开发的 gatsby 网站收集捐款。它使用 firebase 作为后端。我在本地成功接受了带有条纹的捐赠。但是当我推送到 github 时出现 webpack 错误,所以我的更改将在我的 live netlify link 上。这是错误消息的一部分:
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:
错误似乎与我的 loadStripe 方式有关。我在 Layout 组件中使用我的 stripe public 键调用 loadStripe,因为它会在每个页面上呈现,并且我按照 stripe 提供的本文档中的说明进行操作。
Stripe Docs
我也尝试过对其进行异步调用,因为我在此处的文档中看到了这一点。但即使那样似乎也行不通。此外,我去了我的 ContactDonate 页面,在那里我使用了条带组件并在那里使用了 loadStripe,但这给了我一个错误。当我已经在布局组件中加载条带时,在我的 ContactPage 上再次加载条带似乎是多余的。Stripe Docs async
整个应用程序在本地工作(有或没有对 loadStripe 的异步调用)所以我假设我正在正确加载条带。如果我可以提供有关我的项目的任何其他详细信息,请告诉我。
我什至尝试将条带密钥从测试更改为实时。那也不行。
下面的布局实现使用异步加载条带。在此之前我只有下面一行。
const stripePromise = loadStripe('STRIPE_SECRET_KEY');
Layout.js
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.org/docs/use-static-query/
*/
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
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 <sasheem@sasheemdev.com>",
"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-components": "^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.com/gatsbyjs/gatsby-starter-default"
},
"bugs": {
"url": "https://github.com/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>
);
};
这可能是因为 Elements Provider 组件的设置方式在 Gatsby 中的设置方式有所不同。更多相关信息:
https://www.gatsbyjs.org/blog/2019-01-31-using-react-context-api-with-gatsby/
解决方法是从项目根目录中的 gatsby-browser.js
文件中导出 wrapRootElement
函数 [0]。 Gatsby CLI 默认创建此文件,但如果由于某种原因它不存在,您将需要添加它。
在 gatsby-browser.js
中包括 Stripe 如下:
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>
)
}
请务必将 pk_test_xyz
替换为您自己的可发布密钥:
https://dashboard.stripe.com/test/apikeys
完成后,您可以从 Layout.js
组件中删除与 Stripe 相关的代码。
应该可以!
[0] https://www.gatsbyjs.org/docs/browser-apis/#wrapRootElement
WebpackError:找不到元素上下文;您需要将调用 useStripe() 的应用程序部分包装在提供程序中
我正在使用 stripe 为我正在开发的 gatsby 网站收集捐款。它使用 firebase 作为后端。我在本地成功接受了带有条纹的捐赠。但是当我推送到 github 时出现 webpack 错误,所以我的更改将在我的 live netlify link 上。这是错误消息的一部分:
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:
错误似乎与我的 loadStripe 方式有关。我在 Layout 组件中使用我的 stripe public 键调用 loadStripe,因为它会在每个页面上呈现,并且我按照 stripe 提供的本文档中的说明进行操作。 Stripe Docs
我也尝试过对其进行异步调用,因为我在此处的文档中看到了这一点。但即使那样似乎也行不通。此外,我去了我的 ContactDonate 页面,在那里我使用了条带组件并在那里使用了 loadStripe,但这给了我一个错误。当我已经在布局组件中加载条带时,在我的 ContactPage 上再次加载条带似乎是多余的。Stripe Docs async
整个应用程序在本地工作(有或没有对 loadStripe 的异步调用)所以我假设我正在正确加载条带。如果我可以提供有关我的项目的任何其他详细信息,请告诉我。
我什至尝试将条带密钥从测试更改为实时。那也不行。
下面的布局实现使用异步加载条带。在此之前我只有下面一行。
const stripePromise = loadStripe('STRIPE_SECRET_KEY');
Layout.js
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.org/docs/use-static-query/
*/
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
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 <sasheem@sasheemdev.com>",
"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-components": "^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.com/gatsbyjs/gatsby-starter-default"
},
"bugs": {
"url": "https://github.com/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>
);
};
这可能是因为 Elements Provider 组件的设置方式在 Gatsby 中的设置方式有所不同。更多相关信息:
https://www.gatsbyjs.org/blog/2019-01-31-using-react-context-api-with-gatsby/
解决方法是从项目根目录中的 gatsby-browser.js
文件中导出 wrapRootElement
函数 [0]。 Gatsby CLI 默认创建此文件,但如果由于某种原因它不存在,您将需要添加它。
在 gatsby-browser.js
中包括 Stripe 如下:
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>
)
}
请务必将 pk_test_xyz
替换为您自己的可发布密钥:
https://dashboard.stripe.com/test/apikeys
完成后,您可以从 Layout.js
组件中删除与 Stripe 相关的代码。
应该可以!
[0] https://www.gatsbyjs.org/docs/browser-apis/#wrapRootElement