You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Stripe支付表单持续刷新,preventDefault失效问题排查

Stripe支付表单持续重渲染/刷新问题

问题描述

按照Stripe官方示例实现支付表单后,点击表单内外区域时页面会持续重渲染、刷新,怀疑preventDefault未生效,该问题在Chrome、Chrome无痕模式及Safari中均出现,且与已知同类问题不同。


相关代码

PayScreen.tsx

const stripePromise = loadStripe(config.stripePublishableKey)
export default function CreatePaymentScreen() {
  // 根据评论更新后的代码,问题依旧存在

  const { data, isLoading } = useQuery({
    queryFn: async () => await createPaymentIntent(), 
    // 后端创建PaymentIntent的函数
  })
  const clientSecret = data?.intent?.client_secret
  const email = data?.customer?.email

  if (isLoading || !stripe)
   return null
  return (
    <Elements stripe={stripePromise} options={{ clientSecret }}>
        <CheckoutForm email={email} />
    </Elements>
  )
}

CheckoutForm.tsx(完全照搬Stripe官方示例)

import { useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js'

const CheckoutForm = () => {
  const stripe = useStripe()
  const elements = useElements()

  const handleSubmit = async (event: any) => {
    // 阻止默认表单提交行为,避免页面刷新
    event.preventDefault()

    if (!stripe || !elements) {
      // Stripe.js尚未加载完成,需禁用表单提交直到加载完成
      return
    }

    const result = await stripe.confirmPayment({
      // 用于创建Payment Element的Elements实例
      elements,
      confirmParams: {
        return_url: "https://example.com/order/123/complete",
      },
    })

    if (result.error) {
      // 向用户展示错误信息(比如支付信息不完整)
      console.log(result.error.message)
    } else {
      // 用户将被重定向到return_url,部分支付方式(如iDEAL)会先跳转到中间授权站点,再回到return_url
    }
  }

  return (
    <div>
      <PaymentElement />
      <button onSubmit={handleSubmit} disabled={!stripe}>Submit</button>
    </div>
  )
}

export default CheckoutForm

package.json依赖片段

{
  "@stripe/react-stripe-js": "^2.4.0",
  "@stripe/stripe-js": "^2.4.0"
}

问题根源与修复方案

1. 按钮事件绑定错误

CheckoutForm中按钮使用了onSubmit属性,但该属性属于<form>元素,按钮本身没有onSubmit事件,导致handleSubmit中的event.preventDefault()根本不会触发,无法阻止页面默认刷新行为。

修复:
用<form>包裹支付元素和按钮,将提交逻辑绑定到表单的onSubmit事件,同时给按钮设置type="submit":

// CheckoutForm.tsx 中return部分修改为
return (
  <form onSubmit={handleSubmit}>
    <PaymentElement />
    <button type="submit" disabled={!stripe || !elements}>Submit</button>
  </form>
)

2. PayScreen中的无效条件判断

原代码中!stripe是无效判断(未定义stripe变量),导致Elements可能在clientSecret未就绪时就渲染,引发不必要的重渲染。

修复:
将判断条件改为检查clientSecret是否存在:

// PayScreen.tsx 中条件判断修改为
if (isLoading || !clientSecret)
  return null

3. Elements配置引用频繁变化

Elements的options对象每次组件重渲染时都会创建新引用,导致Elements频繁重新挂载,引发页面重渲染。

修复:
用useMemo缓存options对象,确保只有clientSecret变化时才更新:

// PayScreen.tsx 中添加useMemo
import { useMemo } from 'react';

// ...

const options = useMemo(() => ({ clientSecret }), [clientSecret])

return (
  <Elements stripe={stripePromise} options={options}>
    <CheckoutForm email={email} />
  </Elements>
)

内容的提问来源于stack exchange,提问作者not_fubar_yet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:02:05