React Formik : How to useEffect with formik values?

Viewed 3285

I would like to use useEffect to rerender a field if values of formik has changed. But it doesn't work..

Actually I created a little example to show my problem. Here I have one field 'title', if this field has changed (when we write in it) it should call useEffect and print 'update!' but it doesn't!!

const FormikWidgetConfigurator = (props) => {
  useEffect(() => {
     // doesn't work if values has changed
     console.log('update!')
  }, [props.values]);

  return (
    <Form onSubmit={ props.handleSubmit } noValidate>
      <Form.Group className='py-3' >
        <Col md='6' style={{ padding: '0px' }}>
          <Form.Group controlId='title'>
            <Form.Control
              type='text'
              value={ props.values.title }
              onChange={props.handleChange}
            />
          </Form.Group>
        </Col>
      </Form.Group>
    </Form>
  )
}

const WidgetConfigurator = withFormik({
  mapPropsToValues(props) {
    return {
      title: 'No Title'
    };
  },

  validationSchema: props => Yup.object().shape({title: Yup.string()}),

  handleSubmit(values, { setSubmitting }) {// handle submit}
})(FormikWidgetConfigurator);

export default WidgetConfigurator;

EDIT: Actually it works as expected. (i didn't change anything)

Thanks!

2 Answers

Using vanilla Formik your approach works.

Edit Formik Example (forked)

My guess is that the issue is in your custom components, Form.Control, or Form.Group

It's not a great solution, but a hack I found is to have an invisible button inside a Formik form; it has access to all of Formik's attributes and will do whatever logic is needed in its onClick. Then from a useEffect you can simulate the click of that button via document.getElementById("..").click().

// Style it to be invisible
<Button id="testButton" type="button" onClick={() => {
    setFieldValue('test', '123');
    setTouched({});    
    // etc. any Formik action
}}>
</Button> 

useEffect:

useEffect(() => {
    document.getElementById("testButton").click(); // Simulate click
}, [dependency);
Related