use-manage-form
v2.1.1
Published
A react hook used to manage form and form input states
Maintainers
Readme
USE-MANAGE-FORM
The use-manage-form is a React hook used to manage form states in a component. As a React developer, many a time i've come across scenarios where i'll have to manage multiple states and validation logic because of a single form, that's what inspired me to develop this hook and publish it so I and developers like me can use them to make development easier.
Installation
Inorder to install this package, one should run npm install use-manage-form OR yarn add use-manage-form. To install a specific version run npm install use-manage-form@version OR yarn add use-manage-form@version. Replace version with the package version e.g 1.0.0.
How to use the package
To use the package/hook, you import it at the top of your .js/.ts file.
import { useInput, useForm } from "use-manage-form";useInput hook
The useInput hook is responsible for managing each input state, properties and validation. E.g:
const { value, isValid, inputIsInValid, onChange, onBlur, reset } =
useInput(validateFunction);It returns an object containing the
valueof the inputisValidboolean if the input is valid or not (based on the validateFunction)inputIsInValidboolean if the input field is inValid or not (based on the validateFunction and if the input field has been touched)onChangefunction to be executed inorder to change the value of the inputonBlurfunction to be executed to indicate that the input has been touched (to set the inputIsInvalid value properly)resetfunction to be executed to reset the value of the input and inputWasTouched to empty and false respectively
The useInput hook also accepts a function validateFunction as a parameter that should return the input validator. It passes the input value as a parameter to the function validateFunction. E.g:
useInput((/**@type String*/ value) => {
return value.trim() !== "";
});Inorder to update the input value you should pass the onChange function from useInput hook to the input's onChange prop. I.e:
<input
type="text"
onChange={(/**@type Event */ e) => {
onChange(e.target?.value);
}}
id="name"
/>To perform two way binding, you also need to pass the value property from the useInput hook to the input's value prop. I.e:
<input
type="text"
onChange={(/**@type Event */ e) => {
onChange(e.target?.value);
}}
id="name"
value={value}
/>To indicate that the input was touched you'll need to pass the onBlur function from the useInput hook to the input's onBlur prop. I.e:
<input
type="text"
onChange={(/**@type Event */ e) => {
onChange(e.target?.value);
}}
onBlur={() => {
onBlur();
}}
id="name"
value={value}
/>To reset an input, just call the reset function. E.g:
reset();You can use the inputIsInValid property to show some error if the input field is invalid. The difference between the isValid and inputIsInValid properties are
isValidreturnstrueorfalsebased on thevalidateFunctionpassed into theuseInputhook.inputIsInValidreturnstrueorfalsebased on both theisValidandinputWasTouchedproperties.inputIsInValidis used for error stylings. I.e: The input is always invalid because it's empty at first, therefore, theisValidprop returnsfalse. If you use theisValidprop to determine the error styling (Display input error message), it will be displayed when the page is loaded, But if theinputIsInValidprop is used - the error would only be displayed if the user has touched the input or has clicked the submit button. E.g:
<div>
<input
type="text"
onChange={(/**@type Event */ e) => {
onChange(e.target?.value);
}}
onBlur={() => {
onBlur();
}}
value={value}
id="name"
/>
{inputIsInValid && <p className="error-text">Name must not be empty.</p>}
</div>You can rename each property in case you are using multiple useInput . E.g:
const {
value: firstName,
isValid: firstNameIsValid,
inputIsInValid: firstNameInputIsInValid,
onChange: firstNameChangeHandler,
onBlur: firstNameBlurHandler,
reset: resetFirstName,
} = useInput((value) => value.trim() !== "");useForm hook
The useForm hook is used to manage the states of a whole form, it manages the formIsValid state and other functions.
The useForm hook returns three properties namely:
{
executeBlurHandlers,
formIsValid,
reset,
}- The
executeBlurHandlersexecutes all form inputonBlurfunctions passed to theuseFormhook. - The
formIsValidreturnstrue/false, based on the function passed to the useFormhook. - The
resetresets all form inputs passed to theuseFormhook.
The useForm hook accepts an object containing:
blurHandlers: The list of all inputonBlurfunctions to be executed (to be executed when form is submitted, but NOT validated, it sets theinputWasTouchedvalue of all inputs passed into it totrueandinputIsInValidstates to true for invalid inputs).validateOptions: ThevalidateFunctionused to determine if the form is valid or notresetHandlers: The list of all inputresetfunctions (To reset all input values andinputWasTouchedvalues to empty and false respectively)
Therefore, the useForm is to be called this way:
const { executeBlurHandlers, formIsValid, reset } = useForm({
blurHandlers: [firstNameBlurHandler, lastNameBlurHandler, emailBlurHandler],
validateOptions: () => firstNameIsValid && lastNameIsValid && emailIsValid,
resetHandlers: [resetFirstName, resetLastName, resetEmail],
});The onSubmit function passed to the form could be then implemented this way:
const onSubmit = (/**@type Event*/ e) => {
e.preventDefault();
if (!formIsValid) {
executeBlurHandlers();
return false;
}
};
...
return(
<form onSubmit={onSubmit}>
</form>
)At the end our code base should be similar to this
import { useForm, useInput } from "use-manage-form";
const BasicForm = (props) => {
const {
value: firstName,
isValid: firstNameIsValid,
inputIsInValid: firstNameInputIsInValid,
onChange: firstNameChangeHandler,
onBlur: firstNameBlurHandler,
reset: resetFirstName,
} = useInput((value) => value.trim() !== "");
const {
value: lastName,
isValid: lastNameIsValid,
inputIsInValid: lastNameInputIsInValid,
onChange: lastNameChangeHandler,
onBlur: lastNameBlurHandler,
reset: resetLastName,
} = useInput((value) => value.trim() !== "");
const {
value: email,
isValid: emailIsValid,
inputIsInValid: emailInputIsInValid,
onChange: emailChangeHandler,
onBlur: emailBlurHandler,
reset: resetEmail,
} = useInput((value) => value.trim() !== "" && value?.includes("@"));
const { executeBlurHandlers, formIsValid, reset } = useForm({
blurHandlers: [firstNameBlurHandler, lastNameBlurHandler, emailBlurHandler],
validateOptions: () => firstNameIsValid && lastNameIsValid && emailIsValid,
resetHandlers: [resetFirstName, resetLastName, resetEmail],
});
const firstNameInputClasses = firstNameInputIsInValid
? "form-control invalid"
: "form-control";
const lastNameInputClasses = lastNameInputIsInValid
? "form-control invalid"
: "form-control";
const emailInputClasses = emailInputIsInValid
? "form-control invalid"
: "form-control";
const onSubmit = (/**@type Event*/ e) => {
e.preventDefault();
if (!formIsValid) {
executeBlurHandlers();
return false;
}
console.log("SUBMIT", {
firstName,
lastName,
email,
});
reset();
};
return (
<form onSubmit={onSubmit}>
<div className="control-group">
<div className={firstNameInputClasses}>
<label htmlFor="name">First Name</label>
<input
type="text"
onChange={(/**@type Event */ e) => {
firstNameChangeHandler(e.target?.value);
}}
onBlur={() => {
firstNameBlurHandler();
}}
value={firstName}
id="name"
/>
{firstNameInputIsInValid && (
<p className="error-text">Firstame must not be empty.</p>
)}
</div>
<div className={lastNameInputClasses}>
<label htmlFor="name">Last Name</label>
<input
type="text"
id="name"
onChange={(/**@type Event */ e) => {
lastNameChangeHandler(e.target?.value);
}}
onBlur={() => {
lastNameBlurHandler();
}}
value={lastName}
/>
{lastNameInputIsInValid && (
<p className="error-text">Lastname must not be empty.</p>
)}
</div>
</div>
<div className={emailInputClasses}>
<label htmlFor="name">E-Mail Address</label>
<input
type="text"
id="name"
onChange={(/**@type Event */ e) => {
emailChangeHandler(e.target?.value);
}}
onBlur={() => {
emailBlurHandler();
}}
value={email}
/>
{emailInputIsInValid && (
<p className="error-text">
Email must not be empty and must be a valid email.
</p>
)}
</div>
<div className="form-actions">
<button disabled={!formIsValid}>Submit</button>
</div>
</form>
);
};
export default BasicForm;Thank you, if this helped you i would appreciate you star the repo Use-manage-form repo
