jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
34.02k stars 2.79k forks source link

componentWillRecieveProps nextProps for values and erros are out of sync #335

Closed cvburgess closed 6 years ago

cvburgess commented 6 years ago

Bug, Feature, or Question?

Bug (possibly?)

Current Behavior

The componentWillRecieveProps method of a form's child components does not get an updated errors object as part of nextProps. There is a one update delay in the errors object being accurate.

Desired Behavior

If a validationSchema is presented, the values and errors objects should be updated at the same time. This makes building a component like AutoSave reasonable because you only want to save values that have changed if they are error-free.

Suggested Solutions

Info

cvburgess commented 6 years ago

I'm assuming this might happen because they are two separate calls to setState which are async by nature

cvburgess commented 6 years ago

For anyone who stumbles across this, here's how I worked around this.

I just passed the Yup schema to the <AutoSave/> component and manually validate the schema. Its double work, but it's accurate.

import React from 'react';
import PropTypes from 'prop-types';
import { debounce, isEqual } from 'lodash';

const DEBOUNCE_DURATION = 1000;

class AutoSave extends React.Component {
  componentWillReceiveProps(nextProps, nextContext) {
    const { validationSchema } = this.props;
    const newValues = nextContext.formik.values;
    const oldValues = this.context.formik.values;
    const valuesHaveChanged = !isEqual(newValues, oldValues);

    if (valuesHaveChanged) {
      validationSchema.isValid(newValues).then(isValid => isValid && this.saveForm());
    }
  }

  saveForm = debounce(this.context.formik.submitForm, DEBOUNCE_DURATION);

  render() {
    return null;
  }
}

AutoSave.propTypes = {
  validationSchema: PropTypes.shape({}).isRequired,
};

AutoSave.contextTypes = {
  formik: PropTypes.object,
};

export default AutoSave;
jaredpalmer commented 6 years ago

This is because Yup validates asynchronously. Formik updates values immediately, and then errors once validation is completed.

cvburgess commented 6 years ago

Thanks @jaredpalmer - i figured that is why. Passing the validationSchema and doing it myself isn't a bad workaround.