Using React, react-final-form, and the lodash debounce function I would like to validate that a username has not already been used (the field is using react-final-form).
I'm having problems getting the debounce function to return a resolved promise from a fetch request.
I have provide the following codesandbox link to demonstrate my problem:
Please could anyone show me why my code is not working.
The entry point to the validation is from this.isNameUnique call referenced in the validate attribute in
import React from "react";
import { Field, Form } from "react-final-form";
import { debounce } from "lodash";
class DemoForm extends React.Component {
getIsNameUnique = name => {
console.log("getIsNameUnique", name);
// fake fetch request
return async name => {
const asyncResponse = await new Promise(resolve =>
setTimeout(resolve({ name: true }), 1000)
);
console.log("async api response", asyncResponse);
return asyncResponse;
};
};
debounceCreativeName = name => {
console.log("debounceCreativeName", name);
return new Promise(resolve => {
debounce(() => resolve(this.getIsNameUnique(name)), 2000);
});
};
isNameUnique = async name => {
const isNameAvailable = await this.debounceCreativeName(name);
console.log("isNameAvailable", isNameAvailable);
return isNameAvailable;
};
render() {
return (
<Form
onSubmit={() => null}
render={({ handleSubmit, reset, submitting, pristine, values }) => {
return (
<form onSubmit={handleSubmit}>
<Field name="name" validate={this.isNameUnique}>
{({ input, meta }) => {
return (
<input
style={{
display: "flex",
height: "40px",
fontSize: "24px"
}}
autoComplete="off"
{...input}
type="text"
placeholder="Enter the name"
/>
);
}}
</Field>
</form>
);
}}
/>
);
}
}
export default DemoForm;
The Lodash debounce function returns a debounced function that when called will execute a function after X milliseconds pass since its last execution.
Implementation. The following implementation of debounce returns a function that, as long as it continues to be invoked, will not be triggered. The function will be called after it stops being called for N milliseconds.
This sandbox fixes your problem.
You should not create a new debounce function on every render with:
return new Promise(resolve => {
debounce(() => resolve(this.getIsNameUnique(name)), 2000);
});
Instead you should just wrap your whole function isNameUnique
with the debounce (see my sandbox). By creating a new debounce function on every hit, it cannot 'remember' that is was called or that is will be called again. This will prevent the debouncing.
Additionally, by making async getIsNameUnique
you can reduce the complexity of it be just using await.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With