Go Beyond the Ordinary: Challenge yourself to learn about Custom Hooks in React!
One of the complex and ignored features in React JS is custom hooks. Custom hooks are functions that let you reuse stateful logic across different components, without changing their structure or behavior. They are extremely useful for extracting common functionality, simplifying code, and avoiding redundancy/duplicate functions. Custom hooks follow the same rules as built-in hooks, such as useState and useEffect, and can also use other hooks inside them but are not as common as built-in hooks. Here is a very basic example of how to create and use a custom hook:
// A custom hook that returns the current window width
function useWindowWidth() {
// Declare a state variable to store the width
const [width, setWidth] = useState(window.innerWidth);
// Define a function to update the width on resize
function handleResize() {
setWidth(window.innerWidth);
}
// Use the useEffect hook to add and remove the event listener
useEffect(() => {
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []); // Pass an empty array to run the effect only once
// Return the width value
return width;
}
// A component that uses the custom hook
function App() {
// Call the custom hook and get the width
const width = useWindowWidth();
// Render the width in a paragraph
return <p>The window width is {width}px</p>;
}
As you can see, the custom hook useWindowWidth
encapsulates the logic of getting and updating the window width, and returns it as a value. The component App
can use this hook and render the width without worrying about the implementation details. This makes the code more readable, maintainable, and reusable.
Challenges in using Custom Hooks
Custom hooks are a powerful feature that can help you write better React code. However, they are often ignored or misunderstood by many developers. Some of the reasons are:
Custom hooks are not a built-in feature of React, but a convention that relies on the existing hooks API. Therefore, they are not as well documented or promoted as the core features of React.
Custom hooks can be tricky to design and test, as they involve stateful logic and side effects. They also require following some best practices, such as naming them with the
use
prefix, avoiding conditional calls, and using the eslint plugin for hooks.Custom hooks can be hard to understand and debug, especially when they use other custom hooks or complex dependencies. They can also introduce performance issues if they are not optimized or memoized properly.
Advantages of Custom Hooks
Despite the challenges earlier mentioned, custom hooks have some advantages compared to regular hooks like useState
or useContext
which are built-in hooks react provides.
Some advantages of custom hooks over regular hooks are:
Custom hooks can encapsulate complex logic that involves multiple state variables or effects, and make it easier to read and maintain.
Custom hooks can avoid code duplication by sharing common logic across different components that need the same functionality.
Custom hooks can enhance the separation of concerns by isolating the logic from the UI, and make the components more reusable and testable.
Custom hooks can leverage the power of React hooks, such as memoization, dependency tracking, and error handling, without having to implement them manually.
Examples of how Custom Hooks are used to help you get started
To overcome the challenges earlier mentioned, it is important to work more on projects and improve your coding practices by writing more code on custom hooks. Here are some examples of codes that will enable you to learn custom hooks more and be efficient in them. In order to do this you need:
- To design and test custom hooks as pure functions, you can use this example of a custom hook that returns the current user's name and role from a mock API:
// A mock API function that returns the user data
function getUser() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ name: "Alice", role: "Admin" });
}, 1000);
});
}
// A custom hook that returns the user's name and role
function useUser() {
// Declare state variables to store the name and role
const [name, setName] = useState(null);
const [role, setRole] = useState(null);
// Use the useEffect hook to fetch the user data once
useEffect(() => {
getUser().then((user) => {
setName(user.name);
setRole(user.role);
});
}, []); // Pass an empty array to run the effect only once
// Return the name and role values
return [name, role];
}
// A component that uses the custom hook
function App() {
// Call the custom hook and get the name and role
const [name, role] = useUser();
// Render the name and role in a paragraph
return <p>The current user is {name} and the role is {role}</p>;
}
For you to test this custom hook, you can use a tool like React Testing Library to render the component that uses the hook, and assert that the name and role are displayed correctly. You can also mock the API function to control the data that is returned by the hook.
- To follow the best practices of custom hooks, you can use this example of a custom hook that returns a random color from a list of colors:
// A list of colors
const colors = ["red", "green", "blue", "yellow", "pink", "purple"];
// A custom hook that returns a random color
function useRandomColor() {
// Declare a state variable to store the color
const [color, setColor] = useState(null);
// Define a function to generate a random color
function getRandomColor() {
// Get a random index from the colors array
const index = Math.floor(Math.random() * colors.length);
// Return the color at that index
return colors[index];
}
// Use the useEffect hook to set the color once
useEffect(() => {
setColor(getRandomColor());
}, []); // Pass an empty array to run the effect only once
// Return the color value
return color;
}
// A component that uses the custom hook
function App() {
// Call the custom hook and get the color
const color = useRandomColor();
// Render the color in a paragraph
return <p>The random color is {color}</p>;
}
This custom hook follows the rules of hooks, such as naming it with the use
prefix, and avoiding conditional calls. For example, you should not call the hook inside an if statement, like this:
// A component that uses the custom hook conditionally
function App() {
// Declare a state variable to store a flag
const [showColor, setShowColor] = useState(false);
// Call the custom hook only if the flag is true
if (showColor) {
// This is a bad practice and will cause errors
const color = useRandomColor();
}
// Render the color in a paragraph
return (
<div>
<p>The random color is {color}</p>
<button onClick={() => setShowColor(!showColor)}>
Toggle color
</button>
</div>
);
}
This will break the order of hooks, and cause the color variable to be undefined or inconsistent. You should use the eslint plugin for hooks to detect and fix these errors.
- To understand and debug custom hooks, you can use this example of a custom hook that returns the current date and time:
// A custom hook that returns the current date and time
function useDateTime() {
// Declare a state variable to store the date and time
const [dateTime, setDateTime] = useState(new Date());
// Define a function to update the date and time every second
function tick() {
setDateTime(new Date());
}
// Use the useEffect hook to add and remove the interval
useEffect(() => {
const interval = setInterval(tick, 1000);
return () => {
clearInterval(interval);
};
}, []); // Pass an empty array to run the effect only once
// Return the date and time value
return dateTime;
}
// A component that uses the custom hook
function App() {
// Call the custom hook and get the date and time
const dateTime = useDateTime();
// Render the date and time in a paragraph
return <p>The current date and time is {dateTime.toLocaleString()}</p>;
}
In order to inspect the state and effects of this custom hook, you can use the React DevTools to see how the dateTime value changes over time, and how the interval is added and removed. You can also use descriptive names for your custom hook and its arguments, and add comments or documentation to explain their purpose and functionality. You can also avoid using too many custom hooks or nesting them too deeply, as this can make the code harder to follow and maintain.
Conclusion
Custom hooks are a powerful feature of React that can help you write cleaner, more reusable, and more professional code. They are not very common, but they can give you an edge as a developer. There are many more examples and tutorials on custom hooks that you can search online, but I'll stop here for now. I hope you learned something new and useful from this blog. Remember, it's all about constant practice! Happy coding ๐