kilinkis
kilinkis

Reputation: 602

Formik onSubmit - remove form and success message

This is the first time I'm using Formik and I'm facing the following issues: I created this form using a typescript starter provided in the Formik documentation, and it works, but I'd like to show a success message and remove the form once axios returns with status 200.

So,
1. how do I target the form reference inside of the axios call? normally that is as simple as e.target but the event seems not to be available in Formik.
2. how do I access the state of the form in Formik? to toggle the success message.

The full code is available here: https://codesandbox.io/s/throbbing-water-ffl2w

Thanks a lot in advance.

    <Formik
      initialValues={{
        firstName: "",
        lastName: "",
        email: ""
      }}
      // initialStatus={{ // resetForm(); resets this
      //   sent: "nope"
      // }}
      onSubmit={(
        values: Values,
        { setStatus, setSubmitting, resetForm }: FormikActions<Values>
      ) => {
        axios({
          method: "post",
          url: "https://getform.io/f/15faef97-5703-4799-930d-c3e698c99967",
          data: { email: values.email, values }
        }).then(r => {
          setSubmitting(false);
          setStatus("sent");
          //resetForm();
          console.log("Thanks!");
        });
      }}
      render={() => (
        <Form>
          <label htmlFor="firstName">First Name</label>
          <Field
            id="firstName"
            name="firstName"
            placeholder="John"
            type="text"
          />

          <label htmlFor="lastName">Last Name</label>
          <Field id="lastName" name="lastName" placeholder="Doe" type="text" />

          <label htmlFor="email">Email</label>
          <Field
            id="email"
            name="email"
            placeholder="[email protected]"
            type="email"
          />

          <button type="submit" style={{ display: "block" }}>
            Submit
          </button>
        </Form>
      )}
    />

Upvotes: 1

Views: 9495

Answers (3)

awran5
awran5

Reputation: 4536

This is an outdated version of Formik v1.1.2 and I wouldn't recommend to use it as there are some Breaking Changes such as the render method has been deprecated and will be removed in future versions. You may want to use the current version which is v2.1.4

  1. how do I target the form reference inside of the axios call?

Formik passes the values object along with other methods (called FormikBag) inside the onSubmit prop. You can pass these value directly to axios without the need to have your own onSubmit or onChange methods. Please note that <Formik> component has other props. that will give you pretty much full control/access for your needs. That said, I'd recommend to only use Formik state/methods to avoid any side effects or bugs of having the multiple states or handlers.

v2 General Syntax:

<Formik
   initialValues={initialValues}
   // Other Formik props...
   onSubmit = {(Object: form values, Object: Formik Bag ) => {
     // access form values...
   }}
>
 // Access render methods and props (children props)
 {(props) => {
    return (
      <Form>
        <Field> ...
      </Form>
     )
   }
 }
</Formik>

axios Example:

<Formik
  initialValues={initialValues}
  onSubmit={(values) => {
    console.log(values) // Object holds your form values
    axios({
      method: "post",
      url: "url",
      data: { values }
    })
  })
/>

  1. how do I access the state of the form in Formik? to toggle the success message.

You can use Formik setStatus method from FormikBag inside your onSubmit to pass your server response status, then you can access that status via children props Here is an example:


<Formik
  initialValues={initialValues}
  onSubmit={(values, setStatus) => {
    axios({
      method: "post",
      url: "url",
      data: { values }
    })
    .then(res => {
      if (res.status === 200) {
        // 200 means POST method response with success 
        // Pass your server response to Formik
        setStatus({
          sent: true,
          msg: "Message has been sent! Thanks!"
          // Pass more if you need
        })
      }
    })
    .catch(err => {
      // Something went wrong
      setStatus({
        sent: false,
        msg: `Error! ${err}. Please try again later.`
      })
    })
  })
>

  // Later in your code destructuring the children props and use it like so:
  {({ status }) => ( 
    <Form>
      <Field ... />
        {status && status.msg && (
          <p className={`alert ${ status.sent ? "alert-success" : "alert-error"}`}>
            {status.msg}
          </p>
       )}
     <button>Submit</button>
    </Form>
  )}

</Formik>

I did fork your codesanbox and updated the dependencies versions/syntax in this codeSandbox Example. Please note that I'm no typescript expert.

Upvotes: 1

Bogdan Cojocariu
Bogdan Cojocariu

Reputation: 51

What I recommend is using state to control what to show in your component (for some reason I cannot save the codesandbox):

const BasicForm: React.FC<{}> = () => {
  const [isSent, setIsSent] = React.useState(false);

then, the fetch callback:

.then(r =>
...
    setIsSent(true);

Finally in your render function

render={({ isSubmitting, status }) =>
          !isSent ?
            <Form> ... </Form>:
            <div>Success</div>

Upvotes: 4

Kirill Skomarovskiy
Kirill Skomarovskiy

Reputation: 1565

render is a function that gets props. I see that you use setStatus, so you can get status from props and make changes in Form Component

Upvotes: 1

Related Questions