React Stripe Elements在开发中工作正常,但通过Netlify实时部署会抛出Provider.js react stripe elements节点模块文件中的“ Webpack:未定义窗口”。
根据其他建议,我尝试了ComponentDidMount方法,并使用以下方法编辑Provider.js:
if (typeof window !== 'undefined') {
let iInnerHeight = window.innerHeight;
}
两者仍然导致部署失败。
此外,我尝试在StripeProvider组件中设置stripe或apiKey,设置stripe throws错误需要Stripe对象,例如Stripe(...)->使用此get切换时,未定义Stripe,并且apiKey引发窗口未定义错误。
这是我的gatsby-ssr.js文件:
import React from 'react'
import { ShopkitProvider } from './src/shopkit'
import { StripeProvider, Elements } from 'react-stripe-elements'
import Layout from './src/components/Layout'
export const wrapRootElement = ({ element }) => {
return (
<StripeProvider apiKey={process.env.GATSBY_STRIPE_PUBLISHABLE_KEY}>
<ShopkitProvider clientId{process.env.GATSBY_MOLTIN_CLIENT_ID}>
<Elements>{element}</Elements>
</ShopkitProvider>
</StripeProvider>
)
}
export const wrapPageElement = ({ element, props }) => {
return <Layout {...props}>{element}</Layout>
}
一切都按预期完成,但是SSR呈现Webpack窗口未定义的问题。我还在Netlify和.env文件中设置了env变量
答案 0 :(得分:1)
问题在于window
中的StripeProvider
中是否有Stripe对象的检查。这意味着您不能在wrapRootElement
中原始使用它。简单的解决方案是不要在StripeProvider
中使用gatsby-ssr.js
,而只在gatsby-browser.js
中使用它。
但是,由于要用多个服务提供程序包装根目录,并且还需要像这样异步加载Stripe:
// somewhere else vvvvv
<script id="stripe-js" src="https://js.stripe.com/v3/" async />
您最好制作一个可以在gatsby-ssr
和gatsby-browser
中使用的通用包装,以便于维护。
为此,我为StripeProvider
创建了一个包装器,其中Stripe
是根据window
和window.Stripe
的可用性手动启动的。然后,将stripe
实例作为道具传递给StripeProvider
而不是api键。
// pseudo
const StripeWrapper = ({ children }) => {
let stripe,
if (no window) stripe = null
if (window.Stripe) stripe = window.Stripe(...)
else {
stripeLoadingScript.onload = () => window.Stripe(...)
}
return (
<StripeProvider stripe={stripe}>
{children}
<StripeProvider>
)
}
此逻辑应放在componentDidMount
或useEffect
钩中。这是带有钩子的示例:
import React, { useState, useEffect } from 'react'
import { StripeProvider } from 'react-stripe-elements'
const StripeWrapper = ({ children }) => {
const [ stripe, setStripe ] = useState(null)
useEffect(() => {
// for SSR
if (typeof window == 'undefined') return
// for browser
if (window.Stripe) {
setStripe(window.Stripe(process.env.STRIPE_PUBLIC_KEY))
} else {
const stripeScript = document.querySelector('#stripe-js')
stripeScript.onload = () => {
setStripe(window.Stripe(process.env.STRIPE_PUBLIC_KEY))
}
}
}, []) // <-- passing in an empty array since I only want to run this hook once
return (
<StripeProvider stripe={stripe}>
{children}
</StripeProvider>
)
}
// export a `wrapWithStripe` function that can used
// in both gatsby-ssr.js and gatsby-browser.js
const wrapWithStripe = ({ element }) => (
<StripeWrapper>
<OtherServiceProvider>
{element}
</OtherServiceProvider>
</StripeWrapper>
)
答案 1 :(得分:1)
通过在gatsby-config.js中将异步设置为 true
{
resolve: `gatsby-plugin-stripe`,
options: {
async: true
}
}
可以简化上面的代码。
const Stripe = props => {
const [stripe, setStripe] = useState(null);
useEffect(() => {
(async () => {
const obj = await window.Stripe(process.env.STRIPE_PUBLIC_KEY);
setStripe(obj);
})();
}, []);
return (
<>
<StripeProvider stripe={stripe}>
{children}
</StripeProvider>
</>
);
};