条带具有react-stripe-elements,可提供injectStripe
HOC。我们现在在2019年,而HOC不再酷了。 Stripe似乎并不着急,我认为这是因为他们想支持旧版本的React,因此只在寻找最低的公分母解决方案。
我正在寻找一种通过钩子获取stripe
的方法(而不是injectStripe
提供的道具)。
用法看起来像这样
const stripe = useStripe()
这样以后我就可以使用stripe.handleCardSetup
和其他API方法
import { CardElement } from 'react-stripe-elements'
const CardForm = ({secret}) => {
const stripe = useStripe()
const handleSubmit = async () => {
const { setupIntent, error } = await stripe.handleCardSetup(secret)
// ...
}
return (
<>
<CardElement />
<button onClick={handleSubmit} />
</>
)
}
您如何定义现有API和组件中的useStripe
钩子?
stripe
应该和使用injectStripe
钩子后得到的结果相同
关于GH的相关问题:API Review: Hooks & Beyond
答案 0 :(得分:6)
经过一堆反复的试验,我最终得出结论,这很简单。这是采用条纹偷看和其他需要useStripe
钩子的人
// StripeHookProvider.jsx
import React, { useContext, createContext } from 'react'
import { injectStripe } from 'react-stripe-elements'
const Context = createContext()
export const useStripe = () => useContext(Context)
const HookProvider = ({ children, stripe }) => {
return <Context.Provider value={stripe}>{children}</Context.Provider>
}
export default injectStripe(HookProvider)
这样导入StripeHookProvider
并将其添加到您的组件层次结构中。注意:因为它依靠injectStripe
,所以它必须是<Elements>
的子代
<StripeProvider {...{ stripe }}>
<Elements>
<StripeHookProvider>
<MyForm />
</StripeHookProvider>
</Elements>
</StripeProvider>
然后在MyForm中像这样使用它
// MyForm.jsx
import { useStripe } from './StripeHookProvider'
const MyForm = () => {
const stripe = useStripe()
const handleSubmit = () => {
const { setupIntent, error } = await stripe.handleCardSetup(secret ... // and so on
}
}
通过这种方式,您只需要在一个地方进行injectStripe
,它就会被整齐地藏在视线之外。从该代码中可以看到,这不是火箭科学,对于条纹偷看者来说,将其添加到他们的代码中应该没有问题,因为它们在上下文中某个地方引用了<StripeHookProvider>
对象,因此希望完全消除stripe
。
我尝试了很多方法,这是唯一可行的方法。我没有深入研究Stripe的JS代码来了解会发生什么,但是您只能使用stripe
中的injectStripe
。您通过window.Stripe(apiKey)
设置的那个不一样,并且由于无法正确观察<Elements>
而无法正常工作,因此它不知道表单的状态。
也许injectStripe
的孩子必须使用<Elements>
的原因与Stripe团队花一些时间来构建此钩子的原因相同。
答案 1 :(得分:0)
我自己做了,我为您准备了要点:)
useStripe
钩子使用useScript
钩子,它负责加载异步脚本(如带区号)。
要点是:useScript.js
我已经简化了它,您可能也不需要语言环境。
这是useScript:
import React from 'react'
let cache = []
const isCached = src => cache.includes(src)
export const useScript = src => {
const [state, setState] = React.useState({
isLoaded: isCached(src),
hasError: false,
})
React.useEffect(() => {
if (!src || isCached(src)) {
return
}
cache.push(src)
const script = document.createElement('script')
script.src = src
script.async = true
const onScriptLoad = () => {
setState(s => ({...s, isLoaded: true, hasError: false}))
}
const onScriptError = () => {
const index = cache.indexOf(src)
if (index >= 0) {
cache.splice(index, 1)
}
script.remove()
setState(s => ({...s, hasError: true, isLoaded: true}))
}
script.addEventListener('load', onScriptLoad)
script.addEventListener('error', onScriptError)
document.body.appendChild(script)
return () => {
script.removeEventListener('load', onScriptLoad)
script.removeEventListener('error', onScriptError)
}
}, [src])
return state
}
这是useStripe
钩子:
import React from 'react'
import {useScript} from './useScript'
let cache = {}
export const useStripe = ({locale, stripeKey}) => {
const {isLoaded, error} = useScript('https://js.stripe.com/v3/')
const [stripe, setStripe] = React.useState(cache[locale])
React.useEffect(() => {
if (isLoaded && !error && !cache[locale]) {
cache[locale] = window.Stripe(stripeKey, {locale})
setStripe(cache[locale])
}
}, [isLoaded, error, locale])
return {
stripe,
error,
}
}
这只是一个钩子,但是如果您需要上下文API,则可以在Provider中移动useStripe代码!