In this article series, we embark on a journey through the realm of custom React hooks, discovering their immense potential for elevating your development projects. Our focus today is on the "useHover" hook, one of the many carefully crafted hooks available in the collection of React custom hooks.
Github: https://github.com/sergeyleschev/react-custom-hooks
import { useState } from "react"
import useEventListener from "../useEventListener/useEventListener"
export default function useHover(ref) {
const [hovered, setHovered] = useState(false)
useEventListener("mouseover", () => setHovered(true), ref.current)
useEventListener("mouseout", () => setHovered(false), ref.current)
return hovered
}
This lightweight hook leverages the useState and useEventListener hooks from React to keep track of the hover state. By simply passing a ref to the useHover hook, you can start receiving accurate hover events. The hook listens for "mouseover" and "mouseout" events, updating the hovered state accordingly.
One of the key advantages of useHover is its simplicity and reusability. By encapsulating the hover logic within the hook, you can easily use it across multiple components without duplicating code. This promotes clean and maintainable code, saving you time and effort in the long run.
UseHover can be used in a variety of scenarios. Whether you need to highlight an element on hover, trigger additional actions, or dynamically change styles, this custom hook has got you covered. It provides a seamless way to enhance the interactivity and user experience of your React components.
import { useRef } from "react"
import useHover from "./useHover"
export default function HoverComponent() {
const elementRef = useRef()
const hovered = useHover(elementRef)
return (
<div
ref={elementRef}
style={{
backgroundColor: hovered ? "blue" : "red",
width: "100px",
height: "100px",
position: "absolute",
top: "calc(50% - 50px)",
left: "calc(50% - 50px)",
}}
/>
)
}
To demonstrate its power, consider the HoverComponent example above. By applying the useHover hook to the elementRef, the background color of the div dynamically changes between blue and red depending on the hover state. This simple yet effective implementation showcases the potential of useHover in creating interactive and engaging UI components.
Full Version | React Custom Hooks:
https://dev.to/sergeyleschev/supercharge-your-react-projects-with-custom-hooks-pl4
Top comments (16)
You're example should be done with CSS using :hover though. Doing with javascript what can be done with CSS isn't ideal.
Highlight and dynamically change styles are both examples that can easily be accomplished by CSS. If you can do it with CSS, do it with CSS. Javascripts hogs the main thread and is the most expensive resource available.
Hi Martin! Thank you for sharing your thoughts. You make a valid point about utilizing CSS's ":hover" pseudo-class for simple hover effects. CSS is indeed a powerful tool for handling styling and interactions, and it's great for scenarios where the desired effects can be achieved without introducing JavaScript.
However, the React Custom Hook "useHover" is designed to offer more than just basic styling changes. While CSS's ":hover" is excellent for straightforward style adjustments, the "useHover" hook becomes particularly useful when you want to go beyond simple styling changes and incorporate more complex behavior based on hover events.
For instance, imagine you not only want to change the background color of an element on hover but also trigger an API request or toggle some other component's state. In such cases, the "useHover" hook can provide a structured way to manage these interactions without cluttering your component with event listeners and logic.
That is not what you use as your example in the article: you actually suggest that people use it to change style. That is what I am arguing against. If you want both an API-request and a change of style, I would still to the hover using CSS.
It is, sadly, very common among developers, especially when they are deep into React or some other heavy framework, to over engineer things such as this.
Overengineering can be a common pitfall. In capabilities of CSS, like ":hover", for simple styling changes and knowing when to leverage JavaScript, such as the "useHover" hook, for more intricate interactions.
But, the example in the material above should be easy to understand.
This is a nonsense answer? The second sentence does not even make sense?
The example is easy to understand, yes, but it's an anti pattern and nowhere in your article does it mention that it should only be used for more advanced things than simple restyling. Quite the opposite: you give change of the style as a use case.
Out of curiosity are you by any chance using chatgpt to help write parts of text/comments? I don't know why I'm getting these chatgpt vibes.
You're not the only one getting he botty vibes to be honest.
I would appreciate if in
useEventListener
the target object (ref
) comes as 1st argument instead of being the last.Thank you for your feedback regarding the order of arguments in the useEventListener function. Your suggestion is noted and appreciated. While the current implementation places the target object (ref) as the last argument, you could potentially modify the function according to your preference if you are using it in your own projects. Feel free to customize the function to better suit your needs.
Sorry but I don't even know what it means "noted and appreciated" just because it has become such a common reply very often used in quite the opposite way than what the words are telling. Does it mean that you agree that it should be 1st as opposed to last argument? Or does it mean that you don't care or think otherwise and just being polite? If you are not sure why I'm saying it feel free to ask why, if you have reasons behind your option I'd be interested to find out.
The decision on the order of arguments may have been made based on various factors, such as compatibility with other hooks or best practices within the codebase. If you believe that having the target object (ref) as the first argument would be more intuitive or efficient in your use case, you're welcome to customize the function useEventListener to align with your preferences.
I can't think of any reasonable "factors" that would suggest putting target object that is being manipulated as last argument. Can you give some ideas/examples why would that be preferred choice?
I need more info about your project code base to answer your question. And better of course with examples ;) What are you trying to achieve with this change in the argument order.
The reasons why it should be 1st argument - really not just my project as this is fairly fundamental - is because:
target.addEventListener('name', () => { ... })
where the 'target' is modified. Having target as last,addEventListener('name', () => { ...}, target)
is quite strange, I had not seen this practice in any major library in any programming language.What could possibly be reason that 'ref' is last argument?
Like it wooooow, thanks!
You're welcome, Kudzai! 😊
Your appreciation encourages us to continue delving into the realm of custom hooks, uncovering gems like "useHover" that can truly elevate your development endeavors. Happy coding! 🚀