How can Prompt be used to stop navigation on formik dirty state

Viewed 1882

I'm using formik in a reactjs project, and I want to use Prompt from react-router to open a notification before a user leaves and loses changes made to their submission.

I'd expected something like this to work:

<Prompt
    when={formik.dirty}
    message="You have unsaved changes. Are you sure you want to leave?"
/>

My formik block looks like this:

const formik = useFormik({
    initialValues: {
        <values>
    },
    enableReinitialize: true,
    validate,
    onSubmit: values => {
        <submit functional stuff>
    }
}); 

And my form is something like this:

<form id="myForm" onSubmit={formik.handleSubmit}>
    <div className="row">
        <div className="form-group">
            <label htmlFor="name">Name</label>
            <input
                id="name"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.name}
                className="form-control"
                placeholder="Enter name"
                disabled={isDisabled}
            />
            {formik.errors.name ? <div className="text-danger">{formik.errors.name}</div> : null}
        </div>
        <div className="form-group">
            <label htmlFor="subject">Subject</label>
            <input
                id="subject"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.subject}
                className="form-control"
                placeholder="Email subject"
                disabled={isDisabled}
            />
            {formik.errors.subject ? <div className="text-danger">{formik.errors.subject}</div> : null}
        </div>
    </div>
</form>

but it appears that formik.dirty is either not defined or it's not seen as true (despite making changes to the form).

How would I properly use the dirty prop to trigger the Prompt?

1 Answers

I am not sure what kind of setup you have, but I created a PoC with routing which has two tabs (links) for navigation and I am using prompt on tab with formik form component.

import React from "react";
import { Prompt } from "react-router-dom";
import { useFormik } from "formik";

const MyForm = () => {
  const formik = useFormik({
    initialValues: {
      name: "",
      subject: ""
    },
    enableReinitialize: true,
    onSubmit: (values) => {
      alert(JSON.stringify(values, null, 2));
    },
    onChange: (e) => {
      console.log(e);
    }
  });

  return (
    <div>
      <Prompt
        when={!!formik.dirty}
        message={(location) =>
          `Are you sure you want to go to ${location.pathname}`
        }
      />
      <form id="myForm" onSubmit={formik.handleSubmit}>
        <div className="row">
          <div className="form-group">
            <label htmlFor="name">Name</label>
            <input
              id="name"
              type="text"
              onChange={formik.handleChange}
              value={formik.values.name}
              className="form-control"
              placeholder="Enter name"
            />
            {formik.errors.name ? (
              <div className="text-danger">{formik.errors.name}</div>
            ) : null}
          </div>
          <div className="form-group">
            <label htmlFor="subject">Subject</label>
            <input
              id="subject"
              type="text"
              onChange={formik.handleChange}
              value={formik.values.subject}
              className="form-control"
              placeholder="Email subject"
            />
            {formik.errors.subject ? (
              <div className="text-danger">{formik.errors.subject}</div>
            ) : null}
          </div>
          {formik.dirty && <button tye="submit">Save</button>}
        </div>
      </form>
    </div>
  );
};

export default MyForm;

take a look the this codesandbox.

Related