Avoid invalid inputs in react
So you want to avoid your user typing invalid characters in, for example, a numeric input? You only need a custom hook and a regex or a custom function.
Important note!!!: This validation will not replace any validation library and will not work on mobile devices.
your can check the a code and a live demo at code sandbox
Lets build the custom hook
Let's add a custom hook to add an event listener to a specific element and trigger a function when that event happens.
import React, { useEffect } from "react";
type EventListenerParams = {
action: (event: Event) => void; // what do we want to perform with the event
event: string; // what event do we want to listen for
reference: React.RefObject<HTMLInputElement>; // the element that we want to bind to the listener
};
/**
* Add a event listener for a specific event to a specific element
*/
const useEventListener = (params: EventListenerParams): void => {
useEffect(() => {
// on init add event listener
params.reference.current?.addEventListener(params.event, params.action);
// on component unmounted, remove the event listener to avoid performance issues
return () =>
params.reference.current?.removeEventListener(
params.event,
params.action
);
}, [params.reference, params.event, params.action]);
};
export default useEventListener;
With this custom hook, You just need to pass the parameters for each element or event you want to listen for; don't forget to add the return statement to the custom hook, to remove the event listener at component unmount.
What's the difference between bind elements with useRef and getElementById?
By selecting the element with getElementById
you will get the first one that the function finds in the DOM tree, so, if you re-use a component with this validation, it will work only for the first instance
And if you use React.createRef
you will bind an specific instance of an element, so the biding will be unique for each instance
Now lets create a couple of validation functions to test our custom hook
The first one to validate the length of an input value
The second one to validate if the value of an input matches with a regex
/**
* Check if the current length of the input value is minor to a fixed length
* @param maxLength of your input
*/
export function lengthValidator(maxLength: number) {
return function validation(event: Event): void {
const element = event.target as HTMLInputElement;
// if the value length is already equals to maxLength
if (element.value.length >= maxLength) {
// cancel the event and their side effects
event.preventDefault();
}
};
}
/**
* Check if the current value of the input plus the key pressed match with a pattern
* @param regex to compare the input value
*/
export function matchValidator(regex: RegExp) {
return function validation(event: Event): void {
// get the element
const element = event.target as HTMLInputElement;
// get the element current value plus the input key value
const stringToValidate = String(
element.value + (event as KeyboardEvent).key
);
// if input value does not match with the regex
if (!stringToValidate.match(regex)) {
// cancel the event and their side effects
event.preventDefault();
}
};
}
Now lets add some input fields to test our creation
import React from "react";
import "./styles.css";
import useEventListener from "./use-event-listener";
import { lengthValidator, matchValidator } from "./validations";
export default function App() {
const inputRef = React.createRef<HTMLInputElement>();
const inputRef2 = React.createRef<HTMLInputElement>();
/**
* Validates that max-length field never be longer than 10
*/
useEventListener({
action: lengthValidator(10),
event: "keypress",
reference: inputRef
});
/**
* Validates that numbers-only always contains numeric characters
*/
useEventListener({
action: matchValidator(new RegExp("^[\\d]+$")),
event: "keypress",
reference: inputRef2
});
return (
<div className="App">
<div>
<label>Input for with max length of 10</label>
<input
placeholder="Enter a name with no more of 10 characters"
type="text"
id="max-length"
ref={inputRef}
/>
</div>
<div>
<label>Input only for numbers</label>
<input
ref={inputRef2}
placeholder="Enter only numbers"
type="text"
id="numbers-only"
/>
</div>
</div>
);
}
And that's all, now you can use the custom hook in all the components you want, and you can implement your validation functions.
Top comments (0)