Marvin3
Marvin3

Reputation: 6041

Update another component when Formik form changes

There is a basic Formik form:

<Formik
      initialValues={{ email: '', color: 'red', firstName: '' }}
      onSubmit={(values, actions) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }, 1000);
      }}
      render={props => (
        <form onSubmit={props.handleSubmit}>
          <Field type="email" name="email" placeholder="Email" />
          <div>other inputs ... </div>
          <button type="submit">Submit</button>
        </form>
      )}
    />

When any input in it changes (not submits, but changes) - I need to update another component that is outside of <Formik />. The "outside" component should receive all form data.

Is there some way to do it without adding separate change handler for each individual input of a form? Or the solution is to try to insert "outside" component inside <Formik />?

Upvotes: 6

Views: 6576

Answers (3)

Joe Van Leeuwen
Joe Van Leeuwen

Reputation: 335

You should not call setState during the render cycle of a component, as has been suggested:

<Formik
  render={props => (
    setformValues(props.values) // store values in state 'formValues'
    // ...
  )}
/>

Rather, you should call setState as a side-effect. A more verbose, yet better solution would be:

// handle when form values change
const FormikOnChange = ({ onChange }) => {
  const { values } = useFormikContext()

  useEffect(
    () => {
      onChange(values)
    },
    [values]
  )

  return null
}

const App () => {
  const [formValues, setformValues] = useState(initialValues)

  // ...do stuff with form values...

  return (
    <Formik
      render={props => (
        <FormikOnChange onChange={setformValues} /> // store values in state 'formValues'
        // ...
      )}
    />
  )
}

Upvotes: 1

Alejandro Yunes
Alejandro Yunes

Reputation: 85

export const LoginForm: React.FC<Values> = () => {


  const initialValues = { user: "", password: "" };
  const [formValues, setformValues] = React.useState(initialValues);


  return (

              <div>{formValues.user}</div>

              <Formik
                initialValues={initialValues}
                validationSchema={ValidationSchema}
                onSubmit={(values, { setSubmitting, resetForm }) => {

                  setTimeout(() => {
                    //alert(JSON.stringify(values, null, 2));
                    resetForm();
                    setSubmitting(false);
                    setformValues(values);
                  }, 500);
                }}
              >
                {({
                  values,
                  errors,
                  touched,
                  handleChange,
                  handleBlur,
                  handleSubmit,
                  isSubmitting,
                }) => {
                  return (
   <>
                            <TextField
                              label="Usuario"
                              name="user"
                              value={values.user}
                              onChange={handleChange}
                              onBlur={handleBlur}
                              fullWidth
                              color={touched.user && errors.user ? "primary" : "secondary"}
                            />
                            <Error touched={touched.user} message={errors.user} />
                          </> 
                        <div className="pane-form__submit">
                          <Button
                            className={classes.customHoverFocus}
                            variant="contained"
                            type="submit"
                            disabled={isSubmitting}
                            label="CONTINUAR"
                          >Continuar</Button>
                        </div>
                      </Form>
                  )
                }}
              </Formik>


    </>
  );
};

Upvotes: -1

Dani Vijay
Dani Vijay

Reputation: 2258

Formik provides values object which you can make use of to get values outside.

const App = () => {
  const initialValues = { email: '', color: 'red', firstName: '' }

  const [formValues, setformValues] = useState(initialValues);

  const getFormData = values => {
    // access values here
  };
  return (
    <div>
      <h1>Formik take values outside</h1>
      <Formik
        initialValues={initialValues}
        ...
      >
        {props => {
          setformValues(props.values); // store values in state 'formValues'
          getFormData(props.values); // or use any function to get values like this
          return (
            <form onSubmit={props.handleSubmit}>
            ...

Working demo in codesandbox here

Upvotes: 10

Related Questions