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

React+TypeScript集成react-credit-cards时onChange与onFocus报错如何解决

错误原因

  • 核心错误是react-credit-cards组件的number属性接收到了非字符串类型(比如undefined),调用内置的replace方法处理卡号时抛出异常。
  • React的useState不会自动合并对象状态,你原有代码中setState({ [name]: value })、setState({ focus: event.target.name })的写法会直接覆盖整个状态对象,导致card_no、cvc、exp等其他属性丢失变为undefined。
  • 同时使用Formik管理表单状态和自定义useState给信用卡组件传值时,两者状态不同步:自定义的changeHandler没有更新Formik的表单值,持卡人姓名、有效期、CVC三个输入框的状态也没有同步给stateList,导致信用卡组件无法拿到正确的渲染参数。
  • 存在冗余且语法错误的独立onChange方法,内部未定义name和event变量,属于无效代码。

修复方案

按照以下步骤修改代码即可解决问题:

  1. 修正状态更新逻辑,每次更新stateList时先解构原有状态再覆盖新属性,避免其他属性丢失。
  2. 改造changeHandler,同时更新Formik表单状态和stateList,保证两者数据一致。
  3. 给所有和信用卡信息相关的输入框绑定onFocus事件,保证卡片聚焦状态正确切换。
  4. 删除冗余的无效onChange方法。

修复后完整代码

import React, { useState, FocusEvent, ChangeEvent } from 'react'
import Cards from 'react-credit-cards';
import 'react-credit-cards/es/styles-compiled.css'
// 注意根据你的项目实际路径导入缺失的依赖:CustomerDashboardLayout、DashboardPageHeader、CreditCard、Link、Button、Card1、Formik、Box、Grid、TextField、checkoutSchema

const PaymentMethodEditor = () => {
  const [stateList, setState] = useState(initialValues)

  const handleFormSubmit = async (values: any) => {
    console.log(values)
  }

  const focusHandler = (event: FocusEvent<HTMLInputElement>) => {
    // 函数式更新合并原有状态,避免覆盖其他属性
    setState(prev => ({ ...prev, focus: event.target.name }))
  }

  // 柯里化改造,接收Formik的handleChange作为参数,同步更新两份状态
  const changeHandler = (formikHandleChange: (e: ChangeEvent<HTMLInputElement>) => void) => 
    (event: ChangeEvent<HTMLInputElement>) => {
      // 先更新Formik的表单状态
      formikHandleChange(event);
      const { name, value } = event.target;
      // 同步更新给信用卡组件用的状态
      setState(prev => ({ ...prev, [name]: value }))
    }

  return (
    <CustomerDashboardLayout>
      <DashboardPageHeader
        icon={CreditCard}
        title={`${id === 'add' ? 'Add New' : 'Edit'} Payment Method`}
        button={
          <Link href="/payment-methods">
            <Button color="primary" sx={{ bgcolor: 'primary.light', px: '2rem' }}>
              Back to Payment Methods
            </Button>
          </Link>
        }
      />

      <div id="PaymentForm">
        <Cards
          cvc={stateList.cvc}
          expiry={stateList.exp}
          focused={stateList.focus}
          name={stateList.name}
          number={stateList.card_no}
        />
        <Card1>
          <Formik
            initialValues={initialValues}
            validationSchema={checkoutSchema}
            onSubmit={handleFormSubmit}
          >
            {({ values, errors, touched, handleChange, handleBlur, handleSubmit }) => (
              <form onSubmit={handleSubmit}>
                <Box mb={4}>
                  <Grid container spacing={3}>
                    <Grid item md={6} xs={12}>
                      <TextField
                        name="card_name"
                        label="Card Name"
                        fullWidth
                        onBlur={handleBlur}
                        onChange={changeHandler(handleChange)}
                        value={values.card_name || ''}
                        error={!!touched.card_name && !!errors.card_name}
                        helperText={touched.card_name && errors.card_name}
                      />
                    </Grid>
                    <Grid item md={6} xs={12}>
                      <TextField
                        name="card_no"
                        label="Card Number"
                        fullWidth
                        onBlur={handleBlur}
                        onChange={changeHandler(handleChange)}
                        onFocus={focusHandler}
                        value={values.card_no || ''}
                        error={!!touched.card_no && !!errors.card_no}
                        helperText={touched.card_no && errors.card_no}
                      />
                    </Grid>
                    <Grid item md={6} xs={12}>
                      <TextField
                        name="name"
                        label="Name on Card"
                        fullWidth
                        onBlur={handleBlur}
                        onChange={changeHandler(handleChange)}
                        onFocus={focusHandler}
                        value={values.name || ''}
                        error={!!touched.name && !!errors.name}
                        helperText={touched.name && errors.name}
                      />
                    </Grid>
                    <Grid item md={6} xs={12}>
                      <TextField
                        name="exp"
                        label="Exp. Date"
                        fullWidth
                        onBlur={handleBlur}
                        onChange={changeHandler(handleChange)}
                        onFocus={focusHandler}
                        value={values.exp || ''}
                        error={!!touched.exp && !!errors.exp}
                        helperText={touched.exp && errors.exp}
                      />
                    </Grid>
                    <Grid item md={6} xs={12}>
                      <TextField
                        name="cvc"
                        label="CVC"
                        fullWidth
                        onBlur={handleBlur}
                        onChange={changeHandler(handleChange)}
                        onFocus={focusHandler}
                        value={values.cvc || ''}
                        error={!!touched.cvc && !!errors.cvc}
                        helperText={touched.cvc && errors.cvc}
                      />
                    </Grid>
                  </Grid>
                </Box>

                <Button type="submit" variant="contained" color="primary">
                  Save Changes
                </Button>
              </form>
            )}
          </Formik>
        </Card1>
      </div>
    </CustomerDashboardLayout>
  )
}

const initialValues = {
  card_no: '',
  name: '',
  exp: '',
  cvc: '',
  focus: '',
  card_name: '',
}

export default PaymentMethodEditor

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 22:06:04