React Formik 在 <Formik /> 之外使用 submitForm

IT技术 reactjs formik
2021-04-16 17:13:10

当前行为

<Formik
    isInitialValid
    initialValues={{ first_name: 'Test', email: 'test@mail.com' }}
    validate={validate}
    ref={node => (this.form = node)}
    onSubmitCallback={this.onSubmitCallback}
    render={formProps => {
        const fieldProps = { formProps, margin: 'normal', fullWidth: true, };
        const {values} = formProps;
        return (
            <Fragment>
                <form noValidate>
                    <TextField
                        {...fieldProps}
                        required
                        autoFocus
                        value={values.first_name}
                        type="text"
                        name="first_name"

                    />

                    <TextField
                        {...fieldProps}
                        name="last_name"
                        type="text"
                    />

                    <TextField
                        {...fieldProps}
                        required
                        name="email"
                        type="email"
                        value={values.email}

                    />
                </form>
                <Button onClick={this.onClick}>Login</Button>
            </Fragment>
        );
    }}
/>

我正在尝试这个解决方案https://github.com/jaredpalmer/formik/issues/73#issuecomment-317169770但它总是让我返回Uncaught TypeError: _this.props.onSubmit is not a function

当我尝试console.log(this.form)submitForm功能时。

各位大侠有什么解决办法吗?


- Formik 版本:最新 - React 版本:v16 - 操作系统:Mac OS

6个回答

只是为了任何想知道通过 React hooks 解决什么问题的人:

Formik 2.x,如答案所述

// import this in the related component
import { useFormikContext } from 'formik';

// Then inside the component body
const { submitForm } = useFormikContext();

const handleSubmit = () => {
  submitForm();
}

请记住,该解决方案仅适用于Formik 组件的组件,因为它使用上下文 API。如果由于某种原因您想从外部组件手动提交,或者从实际使用 Formik 的组件手动提交,您实际上仍然可以使用innerRefprop。

TLDR ; 如果您提交的组件是 a<Formik>withFormik()组件的子组件,则此上下文答案就像一个魅力,否则,请使用innerRef下面答案。

Formik 1.5.x+

// Attach this to your <Formik>
const formRef = useRef()

const handleSubmit = () => {
  if (formRef.current) {
    formRef.current.handleSubmit()
  }
}

// Render
<Formik innerRef={formRef} />
简单和最佳的解决方案
2021-05-22 17:13:10
Formik 1.5.x 的最佳解决方案。对于Formik 2.x,参见ZEE发布的解决方案
2021-05-29 17:13:10
useRef与 TypeScript 一起使用不要忘记设置 FormikValues 类型useRef<FormikValues>()
2021-06-01 17:13:10
Formik 现在是一个功能组件
2021-06-10 17:13:10
这就是为什么 Formik 组件有一个innerRef道具,如果我是正确的,可以传递你想要附加的参考:github.com/jaredpalmer/formik/blob/...
2021-06-12 17:13:10

您可以将formikProps.submitForm(Formik 的程序化提交)绑定到父组件,然后触发来自父组件的提交:

import React from 'react';
import { Formik } from 'formik';

class MyForm extends React.Component {
    render() {
        const { bindSubmitForm } = this.props;
        return (
            <Formik
                initialValues={{ a: '' }}
                onSubmit={(values, { setSubmitting }) => {
                    console.log({ values });
                    setSubmitting(false);
                }}
            >
                {(formikProps) => {
                    const { values, handleChange, handleBlur, handleSubmit } = formikProps;

                    // bind the submission handler remotely
                    bindSubmitForm(formikProps.submitForm);

                    return (
                        <form noValidate onSubmit={handleSubmit}>
                            <input type="text" name="a" value={values.a} onChange={handleChange} onBlur={handleBlur} />
                        </form>
                    )
                }}
            </Formik>
        )
    }
}

class MyApp extends React.Component {

    // will hold access to formikProps.submitForm, to trigger form submission outside of the form
    submitMyForm = null;

    handleSubmitMyForm = (e) => {
        if (this.submitMyForm) {
            this.submitMyForm(e);
        }
    };
    bindSubmitForm = (submitForm) => {
        this.submitMyForm = submitForm;
    };
    render() {
        return (
            <div>
                <button onClick={this.handleSubmitMyForm}>Submit from outside</button>
                <MyForm bindSubmitForm={this.bindSubmitForm} />
            </div>
        )
    }
}

export default MyApp;
这是hacky的方式。我建议您使用reffrom formik 并在需要的地方使用它
2021-05-23 17:13:10
如何用函数做到这一点?不太确定如何使用书籍。
2021-05-24 17:13:10
@iwaduarte 你的意思是“钩子”:-)?这对我来说是 useRef 的好例子
2021-05-29 17:13:10
添加了“钩子”版本的答案:)
2021-06-01 17:13:10
看起来很鸡肋。如果这不是内部方法,那就太好了。
2021-06-04 17:13:10

我找到的最佳解决方案在此处描述https://stackoverflow.com/a/53573760

在此处复制答案:

将“id”属性添加到您的表单中:id='my-form'

class CustomForm extends Component {
    render() {
        return (
             <form id='my-form' onSubmit={alert('Form submitted!')}>
                // Form Inputs go here    
             </form>
        );
    }
}

然后在表单外的目标按钮的“form”属性中添加相同的Id:

<button form='my-form' type="submit">Outside Button</button>

现在,“外部按钮”按钮将完全等效,就好像它在表单内部一样。

注意:IE11 不支持此功能。

我刚刚遇到了同样的问题,并找到了一个非常简单的解决方案,希望这会有所帮助:

这个问题可以用 plain 解决html如果你id在你标签上放了一个标签,form那么你可以使用按钮的form标签用你的按钮来定位它

例子:

      <button type="submit" form="form1">
        Save
      </button>
      <form onSubmit={handleSubmit} id="form1">
           ....
      </form>

您可以将表单和按钮放在任何地方,甚至可以分开。

然后,此按钮将触发表单提交功能,formik 将捕获像往常一样继续该过程。(只要在呈现按钮时将表单呈现在屏幕上,那么无论表单和按钮位于何处,这都将起作用)

谢谢你,非常干净的解决方案。
2021-05-23 17:13:10

如果您将类组件转换为功能组件,则自定义钩子useFormikContext提供了一种在树的任何位置使用 submit 的方法:

   const { values, submitForm } = useFormikContext();

PS:这仅适用于那些不需要在Formik组件外调用 submit 的人,因此您可以将Formik组件放在组件树中的更高级别,而不是使用 ref ,并使用自定义钩子useFormikContext,但如果真的需要从外部提交,Formik您必须使用useRef .

<Formik innerRef={formikRef} />

https://formik.org/docs/api/useFormikContext

在树下,ref 允许您使用外部 Formik 组件,不是吗?
2021-05-31 17:13:10
问题是一个 6 个单词的句子。一是“外”。你怎么能认为这是一个正确的答案?
2021-06-03 17:13:10
为什么?如果您的根组件是 Formik,则不需要 withFormik
2021-06-13 17:13:10
这应该是公认的答案。另外,值得注意的是useFormikContext只存在于 Formik 2.x
2021-06-14 17:13:10
我认为首选的方法是包装将使用withFormikHoC --> formik.org/docs/api/withFormik提交的组件,以便能够调用 useFormikContext。
2021-06-19 17:13:10