Formik: Migrating from isInitialValid to initialErrors?

Created on 25 Nov 2019  路  10Comments  路  Source: formium/formik

Can someone provide an example of how to migrate isInitialValid to initialErrors? I wrote about my current implementation here #1454.

I'm am implementing v2 and getting the deprecation message for isInitialValid. Any specific example on how to convert this would be great.

stale

Most helpful comment

@jaredpalmer

This is the only solution that seems to work for me. Unfortunately, I still have to use the deprecated isInitialValid. validateOnMount works initially when the form mounts, but when I go forward and backward between pages it doesn't reflect the validationSchema for the current page. In order for it to reflect properly, I have to touch a field, then blur off of it.

Working but deprecated

const [ formValues, setFormValues ] = useState(initialValues);
// ... removed extra code for brevity

function nextPage({ values }) {
    setCurrentPage(Math.min(currentPage + 1, children.length - 1));
    setFormValues(values);
}

function previousPage({ values }) {
    setCurrentPage(Math.max(currentPage - 1, 0));
    setFormValues(values);
}

```jsx
initialValues={ formValues }
isInitialValid={ () => (schema ? schema.isValidSync(formValues) : true) }
enableReinitialize={ true }
validationSchema={ schema }
onSubmit={ handleSubmit }>

Here is how I am showing / hiding the next button
```jsx
<Button
    color="primary"
    variant={ !isLastPage && innerProps.isValid ? null : 'hidden' }
    action={ () => nextPage(innerProps) }>
    { activePage.props.nextLabel || 'Next' }
</Button>

Not working

<Formik
    initialValues={ formValues }
    enableReinitialize={ true }
    validateOnMount={ true }
    validationSchema={ schema }
    onSubmit={ handleSubmit }>

I've also tried to check the errors object to see if it's empty in order to toggle the next button.

<Button
    color="primary"
    variant={ !isLastPage && Object.entries(innerProps.errors).length === 0 ? null : 'hidden' }
    action={ () => nextPage(innerProps) }>
    { activePage.props.nextLabel || 'Next' }
</Button>

Works initially, but going forward and back between pages causes the errors object to be behind in state.

So if I:

  • fill out page 1
  • go to page 2
  • go back to page 1
    then the errors object will contain errors from page 2, so the next button doesn't show up on page 1.

Like I said, the only thing that I've been able to get working is to do isInitalValid with synchronous schema validation.

All 10 comments

I'm currently using dirty state to check if form was changed since initialValues.

<Formik {...props}>
  {({ dirty }) => (
    <form>
      <Button isDisabled={!dirty}>Send</Button>
    </form>
  )}
</Formik>

@Kinbaum have you tried valideOnMount ?

@domeknn it works but causes an uncanny behavior. It flicks/blinks the form, quickly updating isValid from true to false.

@VitorLuizC nice catch, didnt saw this! Tried to use validateSync from Yup, but it throws error :/ Even that validateOnMount didnt change isValidating. With dirty also can be problem while you're autofilling form (like getting delivery address from database and put into form). 馃槩

@VitorLuizC nice catch, didnt saw this! Tried to use validateSync from Yup, but it throws error :/ Even that validateOnMount didnt change isValidating. With dirty also can be problem while you're autofilling form (like getting delivery address from database and put into form). 馃槩

Yeap, I had to use enableReinitialize and put my initialValues in a useMemo. Seems fixed now, but is a little more boilerplate code than before.

const initialValues = useMemo(
  () => ({
    name: user?.name ?? '',
    email: user?.email ?? '',
    ...
  }),
  [user]
);

<Formik
  enableReinitialize
  initialValues={initialValues}
>
  {
    ({ dirty, isValid }) => (
      <Button isDisabled={dirty && !isValid}>Send</Button>
    )
  }
</Formik>

@VitorLuizC Okay, but what's when in initialValues you got valid object? Button is still disabled ?

Yeap. Our UX tell us to keep it disabled and only enable when user change change it.

@jaredpalmer

This is the only solution that seems to work for me. Unfortunately, I still have to use the deprecated isInitialValid. validateOnMount works initially when the form mounts, but when I go forward and backward between pages it doesn't reflect the validationSchema for the current page. In order for it to reflect properly, I have to touch a field, then blur off of it.

Working but deprecated

const [ formValues, setFormValues ] = useState(initialValues);
// ... removed extra code for brevity

function nextPage({ values }) {
    setCurrentPage(Math.min(currentPage + 1, children.length - 1));
    setFormValues(values);
}

function previousPage({ values }) {
    setCurrentPage(Math.max(currentPage - 1, 0));
    setFormValues(values);
}

```jsx
initialValues={ formValues }
isInitialValid={ () => (schema ? schema.isValidSync(formValues) : true) }
enableReinitialize={ true }
validationSchema={ schema }
onSubmit={ handleSubmit }>

Here is how I am showing / hiding the next button
```jsx
<Button
    color="primary"
    variant={ !isLastPage && innerProps.isValid ? null : 'hidden' }
    action={ () => nextPage(innerProps) }>
    { activePage.props.nextLabel || 'Next' }
</Button>

Not working

<Formik
    initialValues={ formValues }
    enableReinitialize={ true }
    validateOnMount={ true }
    validationSchema={ schema }
    onSubmit={ handleSubmit }>

I've also tried to check the errors object to see if it's empty in order to toggle the next button.

<Button
    color="primary"
    variant={ !isLastPage && Object.entries(innerProps.errors).length === 0 ? null : 'hidden' }
    action={ () => nextPage(innerProps) }>
    { activePage.props.nextLabel || 'Next' }
</Button>

Works initially, but going forward and back between pages causes the errors object to be behind in state.

So if I:

  • fill out page 1
  • go to page 2
  • go back to page 1
    then the errors object will contain errors from page 2, so the next button doesn't show up on page 1.

Like I said, the only thing that I've been able to get working is to do isInitalValid with synchronous schema validation.

Hi, @Kinbaum.

I just faced the same issue with initial validation. Tried to use initialTouched with the invalid keys object and it works to me.

Example:

<Formik
        initialValues={initialValues}
        validationSchema={FormSchema}
        initialTouched={{ firstName: true }}
        initialErrors={{ firstName: 'Required' }}
        onSubmit={ handleSubmit }
>

The tip from @domeknn solved for me. I'm only using validateOnMount.

<Formik validateOnMount {...props}>
  {({ isValid }) => (
    <form>
      <button disabled={!isValid}>Send</disabled>
    </form>
  )}
</Formik>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

giulioambrogi picture giulioambrogi  路  3Comments

jordantrainor picture jordantrainor  路  3Comments

green-pickle picture green-pickle  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments

Jungwoo-An picture Jungwoo-An  路  3Comments