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

React Final Form:仅合法字段提交及onSubmit差异问询

Hey there! Let's tackle your two react-final-form issues one by one and get that contact form working properly.

1. How to Prevent Submission Until All Fields Are Valid

Right now, your form is ignoring react-final-form's validation checks because you're using a custom handleSubmit tied directly to the native <form> tag. Here's how to fix this:

  • Use react-final-form's built-in handleSubmit: The render prop gives you a pre-wrapped handleSubmit function that runs validation first. Pass this to the native <form>'s onSubmit instead of your custom method.
  • Move your API logic to the Form component's onSubmit: This callback will only execute if your validate function returns an empty errors object (meaning all fields are valid).
  • Stop using refs: You don't need to manually grab input values—react-final-form collects all field data into the values object that gets passed to the onSubmit function.

2. What's the Difference Between <Form/>'s onSubmit and Native <form>'s onSubmit?

Let's clarify these two to avoid confusion:

  • <Form/> component's onSubmit: This is react-final-form's submission handler. It waits for validation to pass first, then sends the validated values to your function. This is where you should put your fetch request, alert, or any other submission logic.
  • Native <form>'s onSubmit: This is the browser's default submit event. If you bind your own function here (like you did with this.handleSubmit), it runs immediately when the submit button is clicked—bypassing react-final-form's validation entirely. The correct approach is to pass the handleSubmit from the render prop to this event, which triggers the validation workflow before running your submission code.

Here's Your Updated Working Code

import React from 'react';
import { Form, Field } from "react-final-form";

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

// This runs ONLY after validation succeeds
const onSubmit = async values => {
  await sleep(300);
  try {
    const response = await fetch('/contact/send', {
      method: 'POST',
      headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(values), // Use validated values directly
    });
    const data = await response.json();
    console.log('Submission successful:', data);
    
    // Optional: Reset the form after success using the `reset` function from render prop
    // reset();
  } catch (err) {
    console.error('Submission failed:', err);
  }
};

export class ContactPage extends React.Component {
  // No need for constructor or custom handleSubmit anymore!

  render() {
    return (
      <div className="contact">
        <div className="contact__form">
          <Form
            onSubmit={onSubmit}
            validate={values => {
              const errors = {};
              if (!values.firstName) {
                errors.firstName = "Required";
              }
              if (!values.subject) {
                errors.subject = "Required";
              }
              if (!values.email) {
                errors.email = "Required";
              } else if (!values.email.match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) {
                errors.email = "Please enter a valid e-mail address"
              }
              if (!values.message) {
                errors.message = "Required";
              }
              return errors;
            }}
            render={({ handleSubmit, submitting }) => (
              // Use react-final-form's handleSubmit for native form onSubmit
              <form onSubmit={handleSubmit}>
                <Field name="firstName">
                  {({ input, meta }) => (
                    <div>
                      <input {...input} type="text" placeholder="Name" />
                      {meta.error && meta.touched && <span>{meta.error}</span>}
                    </div>
                  )}
                </Field>
                <Field name="subject">
                  {({ input, meta }) => (
                    <div>
                      <input {...input} type="text" placeholder="Subject" />
                      {meta.error && meta.touched && <span>{meta.error}</span>}
                    </div>
                  )}
                </Field>
                <Field name="email">
                  {({ input, meta }) => (
                    <div>
                      <input {...input} type="email" placeholder="E-mail" />
                      {meta.error && meta.touched && <span>{meta.error}</span>}
                    </div>
                  )}
                </Field>
                <Field name="message">
                  {({ input, meta }) => (
                    <div>
                      <textarea {...input} placeholder="Message" />
                      {meta.error && meta.touched && <span>{meta.error}</span>}
                    </div>
                  )}
                </Field>
                <div className="buttons">
                  <button type="submit" disabled={submitting}>
                    Submit
                  </button>
                </div>
              </form>
            )}
          />
        </div>
      </div>
    );
  }
}

export default ContactPage;

Key Changes Made:

  • Removed the custom handleSubmit and constructor—react-final-form handles the submission flow now.
  • Moved your fetch logic into the Form component's onSubmit function, which only runs when validation passes.
  • Eliminated all refs since react-final-form manages input values in the values object.
  • Passed the render prop's handleSubmit to the native <form> to trigger validation before submission.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:22:06