Custom hooks are an amazing thing that happened with React. It brings to us the ability to create beautiful components and move a lot of business logic to hooks. Here is the list of the 3 most used custom hooks in my everyday work during the last month.
We’re using this hook in form inputs, where we need to take the user’s inputs with some delay. It can be used for example for cases when we want to send a search request for autosuggestions in fields, but we don’t want to send requests on every input change. Instead of this, we take the input’s value with a little delay.
As usual, we started by creating an empty hook. Hook work with generics as we can work with different data types. Hook takes 2 arguments: initial value and delay in milliseconds. And we return delayValue
export const useDelay = <T>(value: T, delay: number): T => {
const [delayValue, setDelayValue] = useState<T>(value);
return delayValue;
};
Then we will add useEffect
to wrap timeout logic. It will execute on every value or delay change and return the delayed value in the target timeout
useEffect(() => {
const handler = setTimeout(() => {
setDelayValue(value);
}, delay);
return (): void => {
clearTimeout(handler);
};
}, [value, delay]);
Full solution:
export const useDelay = <T>(value: T, delay: number): T => {
const [delayValue, setDelayValue] = useState<T>(value);
useEffect(() => {
const handler = setTimeout(() => {
setDelayValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return delayValue;
};
In the current project, we use many Custom Events. Such events help us to share data between components in cases when we don’t need to put it in the Redux store for example or even to share data between separate applications.
Hook is very small and simple:
export const useCustomEvent = (
event: AppCustomEvents,
listener: EventListenerOrEventListenerObject
): void => {
useEffect(() => {
window.addEventListener(event, listener);
return () => {
window.removeEventListener(event, listener);
};
}, []);
};
We use useEffect hook with empty array as a dependency to execute it on component mount. It ads eventListener to window, and in return function we remove listener to avoid memory leaks.
Than we can just call this hook when we need it:
useCustomEvent(‘user-click‘, handleUserClick)
The last hook is a general solution to work with API requests. I think that many developers use it in variations, but maybe it still will be useful for someone
A simple variant can look something like this:
export function useAPI((options): APIOptions{
const [loading, setLoading] = useState<boolean>(true);
const [data, setData] = useState<T>();
const getData = (): void => {
httpService
.sendRequest<T>({
url: options.url,
data: options.data
})
.then((response) => {
if (response?.data) {
setData(response.data);
}
})
.finally(() => {
setLoading(false);
});
};
useEffect(() => {
getData();
}, []);
return { loading, data };
});
We use our custom httpService
to work with requests, but there can be any other solution: custom variant, fetch, Axios. So, by component mount our hook will call API, save data and set loading
flag to false. Once again I want to notice that this is a very basic solution and in our app, it’s more complex. The idea is that we can create any business logic we need and then easily use it in our application