ReactJS - Formik表单在按下回车键时未触发提交

14

我使用Formik在React中编写了以下表单:

import React, { FunctionComponent } from 'react';
import { NavLink } from 'react-router-dom';
import { object, string } from 'yup';
import { Formik, FormikActions, Field, FormikProps } from 'formik';
import SimpleInput from './Fields/SimpleInput';
import FieldError from './Fields/FieldError';

interface FormValues {
  email: string;
  password: string;
}
interface OwnProps {
  onSubmit: (data: FormValues) => any;
}

const validationSchema = object().shape({
  email: string()
    .email('Please enter a valid email address')
    .required('Email is a required field'),
  password: string()
    .min(8)
    .required('Password is a required field'),
});

type Props = OwnProps;

const LoginForm: FunctionComponent<Props> = ({ onSubmit }) => {
  const initialValues = {
    email: '',
    password: '',
  };

  const onFormSubmit = async (values: FormValues, { setSubmitting }: FormikActions<FormValues>) => {
    await onSubmit(values);
    setSubmitting(false);
  };

  return (
    <Formik
      onSubmit={onFormSubmit}
      initialValues={initialValues}
      validationSchema={validationSchema}
      render={({ handleSubmit, isSubmitting }: FormikProps<FormValues>) => (
        <form className="ipx-form sign" onSubmit={handleSubmit}>
          <h1>Sign in</h1>
          <div className="ipx-register-here">
            ( Don&#39;t have an account? ) &nbsp;
            <NavLink to="/register">Register here</NavLink>
          </div>
          <br />
          <Field name="email" type="email" component={SimpleInput} label="Email Address" placeholder="Email" />
          <FieldError name="email" />
          <br />
          <br />
          <div className="fields">
            <Field name="password" type="password" component={SimpleInput} label="Password" placeholder="Password" />
            <FieldError name="password" />
          </div>
          <br />
          Forgot <NavLink to="/forgot-password">password?</NavLink>
          <br />
          <button className="button ipx-submit-button" id="ipx-login-submit" type="submit" disabled={isSubmitting}>
            <span className="ladda-label">Sign in</span>
          </button>
        </form>
      )}
    />
  );
};

export default LoginForm;

如果我点击按钮提交表单(它会发送Redux操作并记录用户登录),那么一切都很正常,但是当我尝试使用Return / Enter键提交表单时,它无法捕获事件。我尝试在 <form> 元素的 onSubmit 属性中记录事件,但是根本没有触发任何按 Enter 键的事件。这个相同的表单之前使用 redux-form 编写,Return 键功能正常。
起初我认为可能是异步表单处理引起的问题,但是我切换到了常规同步函数,也不起作用。
有人遇到类似的问题吗?如果是,请分享任何修复方法。
谢谢! Codesandbox

你确定验证通过并且字段不为空吗? - dfsq
1
@dfsq 是的,如果我用鼠标指针单击提交按钮,表单就可以正常提交。只有回车键不起作用。事件根本没有触发。我尝试在表单的 onSubmit 属性中记录事件,但当我按下回车键时它根本不记录任何内容。 - Andrej Naumovski
添加一个监听器以响应按下“Enter”键是否可行? - Thomas Brok
你解决了吗? - H S W
4个回答

6
我在你的 Codesandbox 上解决了这个问题,方法是删除 SimpleInput 组件中应用的 {...rest} 属性扩展。这会添加一些奇怪的属性,似乎会干扰标准表单字段行为。
您可以在此处查看正确的回车提交行为:https://codesandbox.io/s/dark-star-r0liq 在我的代码中,我使用标准的 HTML <form> 而不是 Formik 的 <Form>,所以当我遇到这个问题时,我必须确保我的提交按钮具有 type="submit" 属性,以及与 Formik 的 handleSubmit 方法连接的 onClick 处理程序。然后回车提交行为开始正常工作。
相关官方 repo 问题:https://github.com/jaredpalmer/formik/issues/1418

是的,这是一段时间以前的事情,但我现在记得了,从输入中删除 {...rest} 属性正是我们(当时的同事之一)找到的解决方案。 - Andrej Naumovski
请注意,这会导致表单被提交两次。 - Michał Pietraszko

6
我发现解决这个问题的最好方法是在 Formik 的 HTML 表单元素的 onKeyDown 事件中调用 handleSubmit() 方法。
      <Formik
        initialValues={{
          login: '',
          senha: ''
        }}
        onSubmit={(values, { setErrors }) => {
          this.submitSignin(values, setErrors);
        }}
      >
        {props => {
          const {
            values,
            handleChange,
            handleBlur,
            handleSubmit,
          } = props;
          return (
            <form 
              onSubmit={handleSubmit} 
              onKeyDown={(e) => {
                if (e.key === 'Enter') {
                  handleSubmit();
                }
              }}>
             <input 
               id="login"
               value={values.login}
               onChange={handleChange}
               onBlur={handleBlur} />
             <input 
               id="senha"
               value={values.senha}
               onChange={handleChange}
               onBlur={handleBlur} />
            </form>
          }
        </Formik>

Jared Palmer(Formik的创建者)建议不要这样做:["一般来说,您不应该实现onKeyPress"](https://github.com/jaredpalmer/formik/issues/1418#issuecomment-483657274) - Daniel Galarza

1
如果您直接将所有道具传递给自定义组件,则会遇到此问题。正如文档中所示,您必须在将其余部分传递给自定义组件之前删除form道具。

简而言之,这是不正确的:

const CustomInput = (props: React.InputHTMLAttributes<HTMLInputElement> & FieldProps) => {
  return <input {...props} />;
};

这是正确的:
const CustomInput = (props: React.InputHTMLAttributes<HTMLInputElement> & FieldProps) => {
  const { form, field, ...rest } = props;
  return <input {...field} {...rest} />;
};

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接