拆分信用卡到期日 onChange

Splitting Credit Card Expiration Date onChange

所以我需要在我的 formData 中将信用卡到期日期分成两个单独的值。

这是我的组件设置方式。

const [ formData, setFormData ] = useState({
email: '',
password: '',
username: '',
card_num: '',
cvv_code: '',
cc_exp: '',
cc_exp_year: '',
cc_exp_month,
first_name: '',
last_name: '',
    })

我在这里也解构了所有的表单数据:

const { email, password, username, card_num, cvv_code, cc_exp, cc_exp_year, cc_exp_month, first_name, last_name } = formData;

我的 onChange 函数在这里:

const onChange = e =>  {
setFormData({ ...formData, [e.target.name]: e.target.value })
  }

一个

当我输入 cc_exp 的到期日期时,我得到 MM/YY 的正确格式,但我需要将该值拆分为 cc_exp_month 和 cc_exp _年。所以我的问题是,在 / 处拆分字符串的最佳位置在哪里,然后如何将它们添加到 formData 中的那些值。

我已经尝试在 onSubmit 函数中使用 setFormData 来简单地在事后添加值:

const onSubmit = e => {
        e.preventDefault();
        setFormData(formData => ({
            ...formData,  // shallow copy previous state
            cc_exp_month: cc_exp.split('/')[0], // add new property values
            cc_exp_year: cc_exp.split('/')[1],
            username: email
          }));
        dispatch(createMembership(formData, id));
    }

我认为执行此操作的最佳位置是在发送数据之前的 onSubmit。这样我就不必将函数链接在一起,因为我真的不确定在哪里添加它。因此,在设置 cc_exp 并且所有表单数据都存在之后,我试图拆分该值,然后在提交数据之前将其应用于这些其他值 cc_exp_month & cc_exp_year。但是当我点击提交时,月份和年份不显示。但是如果我点击两次提交(没有人会这样做),那么数据就会正确地显示在 formData 中。所以它就像 setFormData 出于某种原因不想在 onSubmit 中添加新的 exp 数据。

第二次调用setFormData不能指望formData新更新的值,因为钩子是异步的。您可能想尝试使用两个新值调用 setFormData() 一次。

setFormData({
  ...formData,
  cc_exp_month: cc_exp.split('/')[0],
  cc_exp_year: cc_exp.split('/')[1]
})

当你像

一样将多个更新加入队列时
setFormData({...formData,  cc_exp_month : cc_exp.split('/')[0] })
setFormData({...formData,  cc_exp_year : cc_exp.split('/')[1] })

每个都使用相同的未更新 formData 值并覆盖先前排队的更新。从以前的状态更新时,您应该使用功能状态更新。如果没有单独的更新更新需要以前的临时更新,您还可以将所有更新合并为一个更新。使用数组解构赋值创建cc_exp_monthcc_exp_year变量,然后在返回的状态值中使用对象shorthand赋值。

const [cc_exp_month, cc_exp_year] = cc_exp.split('/');

setFormData(formData => ({
  ...formData,  // shallow copy previous state
  cc_exp_month, // add new property values
  cc_exp_year,
}));

更新

React 状态更新是异步处理的,因此拆分 CC 过期和排队状态更新不会立即更新 formData。请参阅此 和解释。

const onSubmit = e => {
  e.preventDefault();
  setFormData(formData => ({ // <-- returns state for next render cycle
    ...formData, 
    cc_exp_month: cc_exp.split('/')[0],
    cc_exp_year: cc_exp.split('/')[1],
    username: email
  }));
  dispatch(createMembership(formData, id)); // <-- state from this render cycle
}

您有几个选择:

  1. 使用 useEffect 挂钩更新 cc_exp_monthcc_exp_year 属性,特别是在 formData.cc_exp 属性 更新时。

    useEffect(() => {
      setFormData(formData => {
        const [cc_exp_month, cc_exp_year] = formData.cc_exp.split('/');
        return {
          ...formData,
          cc_exp_month,
          cc_exp_year,
        }
      });
    }, [formData.cc_exp]);
    

    请谨慎使用此方法,因为通常应避免更新 useEffect 回调中可能位于效果的依赖项数组中的任何内容。 不要更新 formData.cc_exp 值,因为这会创建渲染循环!

  2. 计算要在提交处理程序中提交的表单数据对象,不要费心在状态中存储本质上重复的数据,因为已经存在 formData.cc_exp 状态。

    const onSubmit = e => {
      e.preventDefault();
    
      const [cc_exp_month, cc_exp_year] = formData.cc_exp.split('/');
    
      const data = {
        ...formData,
        cc_exp_month,
        cc_exp_year,
      };
    
      dispatch(createMembership(data, id));
    }
    

    在我看来,第二种选择是首选方法,因为它具有较少的移动部件,并且避免了无关的状态更新和重新呈现。 cc_exp_monthcc_exp_year 很容易从状态派生,派生状态不属于状态。