'Yup / Formik async validation with debounce
How can debounce be applied to the async validation below (code from Yup's github) ?
let asyncJimmySchema = string().test(
'is-jimmy',
'${path} is not Jimmy',
async (value) => (await fetch('/is-jimmy/' + value)).responseText === 'true',
});
Solution 1:[1]
You can implement it by your self by using lodash.debounce
:
import { debounce } from "lodash";
// .....
const ASYNC_VALIDATION_TIMEOUT_IN_MS = 1000;
const validationFunction = async (value, resolve) => {
try {
const response = await fetch('/is-jimmy/' + value);
resolve(response.responseText === 'true');
} catch (error) {
resolve(false);
}
};
const validationDebounced = debounce(validationFunction, ASYNC_VALIDATION_TIMEOUT_IN_MS);
Then in the validation scheme:
let asyncJimmySchema = string().test(
'is-jimmy',
'${path} is not Jimmy',
value => new Promise(resolve => validationDebounced(value, resolve)),
});
Solution 2:[2]
I think this should work. It's copying the solution from just-debounce-it but returning a Promise
right away, which is what Yup expects.
const asyncDebouncer = (fn, wait, callFirst) => {
var timeout;
return function() {
return new Promise(async (resolve) => {
if (!wait) {
const result = await fn.apply(this, arguments);
resolve(result);
}
var context = this;
var args = arguments;
var callNow = callFirst && !timeout;
clearTimeout(timeout);
timeout = setTimeout(async function() {
timeout = null;
if (!callNow) {
const result = await fn.apply(context, args);
resolve(result);
}
}, wait);
if (callNow) {
const result = await fn.apply(this, arguments);
resolve(result);
}
});
};
};
let asyncJimmySchema = string().test(
'is-jimmy',
'${path} is not Jimmy',
asyncDebouncer((value) => (await fetch('/is-jimmy/' + value)).responseText === 'true', 400),
});
Solution 3:[3]
Make sure that you are not creating a new instance of the debouncer each time:
import { debounce } from 'lodash'
const isJimmy = async (value,resolve) => {
const response = await fetch('/is-jimmy/' + value))
resolve(response.responseText === 'true')
}
const debounceInstance = (func,delay=1000) => {
const funcDebounced = debounce(func,delay)
return (newValue) =>
new Promise(resolve =>
funcDebounced(newValue,resolve))
}
//BAD - creates a new instance on each call
const asyncJimmySchema = string()
.test(val=> debounceInstance(isJimmy)(val)});
//GOOD - same instance for each call
const asyncJimmySchema = string()
.test(debounceInstance(isJimmy))}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Alex |
Solution 2 | christo8989 |
Solution 3 |