Using Custom Hooks in ReactJs is the Icing on the Cake — Part1
In today’s rapidly changing world, ReactJS has gained significant attention. One of the most appealing aspects of ReactJS is its hooks, especially the ability to create custom hooks, which allows for more flexible and reusable logic.
Let’s explore the usefulness of React hooks, particularly the power they offer through the creation of custom hooks.
Before I demonstrate how to create custom hooks, let’s first understand the definition of hooks.
What Hooks ?
In ReactJS, hooks are special functions that allow you to use state and other React features in functional components. Here are some key points about hooks:
- Introduction: Hooks were introduced in React 16.8.
- Purpose: They enable you to add state, lifecycle methods, and other logic to functional components, which previously required class components.
- Built-in Hooks: React provides several built-in hooks, including:
- useState: For adding state to functional components.
- useEffect: For managing side effects such as data fetching or DOM manipulation.
- useRef: For accessing and interacting with DOM elements or persisting mutable values.
- To learn more about the hooks created by the ReactJS team, please visit react.dev.
Now, let’s create some custom hooks that we can use in our day-to-day development.
useLocalStorage & useSessionStorage
These two hooks are designed to help you store data in localStorage and sessionStorage.
// hooks/useStorage.ts file
type StorageValue = Record<string any>;
const useStorage = (storageObject: Storage) => {
const getStore = <T: StorageValue>(key: string): T | null => {
const item = storageObject.getItem(key);
return item ? JSON.parse(item) : null;
};
const setStore = (key: string, value: StorageValue) => storageObject.setItem(key, JSON.stringify(value));
const removeStore = (key: string) => storageObject.removeItem(key);
const clearStore = () => storageObject.clear();
return {
getStore,
setStore,
removeStore,
clearStore
};
};
const useLocalStorage = () => {
return useStorage(localStorage);
};
const useSessionStorage = () => {
return useStorage(sessionStorage);
};
export { useLocalStorage, useSessionStorage };
useTodo
This hook is designed to assist with creating, removing, and managing todo item
// hooks/useTodo.ts file
import { useCallback, useEffect, useMemo, useState } from 'react';
// Also you can import useStorage hooks here where you can storage the data
// into localStorage to have track which of your todos after refreshing browser
// the as well.
import useStorge from "./hooks/useStorage";
interface Todo {
id: number;
name: string;
isCompleted: boolean;
}
const useTodo = () => {
const { getStore, setStore } = useStorage();
const [todos, setTodos] = useState<TodoList[]>(getStore('todos') ?? []);
const [nextTodoId, setNextTodoId] = useState(0);
const addTodo = useCallback((value: string) => {
if(value.trim()){
const newTodos = {
id: nextTodoId,
name: value.trim(),
isCompleted: false
};
setTodos(prevTodos => [...prevTodos, newTodos];
setNextTodoId(prevNextTodoId => prevNextTodoId + 1);
}
}, [nextTodoId]);
const removeTodo = useCallback((todo: TodoList) => {
const updateTodosAfterRemoved = todos.filter((item) => item.id !== todo.id);
setTodos(updateTodosAfterRemoved);
}, [todos]);
const completeTodo = useCallback(todo: TodoList) => {
setTodos((prevTodos) =>
prevTodos.map((item) =>
item.id === todo.id ? {...item, isCompleted: !item.isCompleted } : item
)
);
}, [setTodos]);
const completedAllTodos = useCallback(() => {
setTodos((prevTodos) =>
prevTodos.map((item) => ({
...item,
isCompleted: !item.isCompleted
});
}
}, [setTodos]);
const checkAllTodoCompleted = useMemo(() => {
return todos.every((todo) => todo.isCompleted);
}, [todos]);
useEffect(() => {
setStore('todos', todos);
}, [todos]);
return {
todos,
addTodo,
removeTodo,
completeTodo,
completedAllTodos,
checkAllTodoCompleted
};
};
export default useTodo;
useCounter
This hook is designed to implement a counter with increment and decrement functionality.
// hooks/useCounter.ts file
import { useState } from 'react';
const useCounter = () => {
const [counter, setCounter] = useState(0);
const increment = () => {
setCounter(prevCounter => prevCounter + 1;
};
const decrement = () => {
setCounter(prevCounter => prevCounter - 1;
};
const reset = () => {
setCounter(0);
}
return {
counter,
increment,
decrement
};
};
export default useCounter;
useEffectOne
This hook is designed to execute side effects only once.
// hooks/useEffectOne.ts file
import { useEffect } from 'react';
const useEffectOne = (effect: () => void) => {
useEffect(effect, []);
};
export default useEffectOne;
That it’s for now,
Conclusion
I’ve put together this small effort in creating custom hooks to help you better understand how to create your own.
I hope you find this article helpful! If there are any features you think I missed or should have covered, feel free to share your thoughts in the comments below.
Happy coding…!!! ✍️💪