Uniforms: [QUESTION]: Asynchronous validation and debouncing

Created on 8 Jun 2020  路  6Comments  路  Source: vazco/uniforms

Hi,

I have a form that I need to validate some fields asynchronously.
My issue is that I do not want the validation to be called every time a key press is made on the specific field, but would prefer to have it run when the user is done typing.

So what I did was wrap my async function in a debounce.

It seems to work, but my issue is after I submit and I run my submitSuccess handler, I get this error.

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application.

And it goes away if I remove the debounce.

Here is my async validation function and submitSuccess handler.

  const handleAsyncValidation = debounce(async (model, error, callback) => {
    const details = [];

    console.log('handleAsyncValidation called')

    if (!isEmpty(model.email)) {
      if (await handleCheckEmailInUse(model.email) === true) {
        details.push({
          name: 'email', 
          message: i18n.t("Users.emailInUseError")
        });
      }
    }

    return callback(details.length ? { details: concat(get(error,'details',[]),details) } : error);        
  },800);

  const handleSubmitSuccess = (currentUser) => {
    console.log('handleSubmitSuccess called')

    // empty client cache and redirect
    props.client.resetStore().then(() => {
      // set user's language
      let language = get(currentUser,'language',i18n.language);
      if (i18n.language !== language) i18n.changeLanguage(language);            

      let redirect = query.get('redirect');

      if(isEmpty(redirect)){
        navigateTo(CompileRoute('Route.home'));
      }else{
        navigateTo(decodeURIComponent(redirect));
      }
    });        
  }

Do you have any suggestions on how I could handle the async validation?

I do not want to change the validation to onSubmit because I like the fact that for any non asynchronous validation, it instantly informs the user of the errors, so I would like to keep that feature.

Hope you can guide me, thanks for your help.

bug

All 6 comments

Hi @simplecommerce. What uniforms version are you using? It would be great to have a minimal reproduction. I guess it shouldn't be the case in v3, but we may fix it in v2 anyway.

Hi @radekmie, thanks for the follow-up, I will try to make a working example for you so you can see what I am trying to achieve, thank you!

I am using version 2.6.7

@radekmie Just to let you know, I have done some tests and I am not able to reproduce it on a sandbox environment.

I am suspecting it is something else I am using with the library that is causing the problem.
Might be the way I am using react-apollo, I will keep testing on my end to confirm the issue.

@radekmie Hi, I have done further testing and I noticed that the issue happens when I set a cookie when the form submission calls the success handler.

It causes my form to re-render.

Is there any particular reason why the async validation would be re-called if the form itself is re-rendered?

The weird thing is I can't reproduce it on the sandbox but it happens every time in my code.

I am trying to figure out why it would trigger the async.
The only way I am able to prevent it, is by calling form.reset() in my onSubmit before it calls my onSubmitSuccess handler.

UPDATE: Ok so the issue was definitely because of the cookies being set, I am using react-cookie with universal-cookie and the withCookies HOC was wrapping my component that rendered the form, and calling the set function on the cookies, would cause it to re-render my form and for whatever reason, call the async validation.

What I did to fix it, was use React.useMemo on my form and watch for a specific prop that would require re-rendering. It seems to work now, but I stll find it odd that I was not able to reproduce this issue on the sandbox.

@simplecommerce You figured it out and that's great! The validation happens on render only when the schema/validator or model change. If you are using AutoForm, then model shouldn't change. If you are using AutoForm and manage the state (model) anyway, consider using ValidatedQuickForm or ValidatedForm instead.

@radekmie Thanks a lot for your link, I was able to really dig in and figure out the problem.

This was the cause.

if (this.props.schema !== schema || this.props.validator !== validator) {

It was going in this condition, and I noticed it was because in my custom component, I was generating the schema bridge on every render, even if in my eyes the values were the same, I suppose it differed in that instance, so I used useMemo on it and it fixed it.

Thanks again!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tab00 picture tab00  路  8Comments

thearabbit picture thearabbit  路  8Comments

cyclops24 picture cyclops24  路  6Comments

rereradu picture rereradu  路  7Comments

radekmie picture radekmie  路  8Comments