useHug: Creating custom React Hooks 🥰
Tags: react, webdev, javascript
Published: 2021-02-14 15:16:01

---
title: useHug: Creating custom React Hooks 🥰
published: true
description: Learn how to pull behaviors out of components and into custom hooks with React
tags: react, webdev, javascript
//cover_image: https://direct_url_to_image.jpg
---

Building custom hooks is a great way to encapsulate behaviors and reuse them throughout your application. To demonstrate this, we're going to build out the idea of "hugging" elements of our UI. Our huggable behavior will:

- Change the mouse cursor on hover (we want our user to know what needs a hug).
- Scale the element down on click (this is a firm hug, some squishiness is expected).
- Change the mouse cursor while clicking (to show our appreciation).

I find the first step to making something reusable is to use it once, so let's implement this in a component:

```jsx
import React, { useState } from "react";
import { animated, useSpring } from "react-spring";

const Huggable = () => {
  const [hovering, setHovering] = useState(false);
  const [pressed, setPressed] = useState(false);
  const animationProps = useSpring({
    transform: `scale(${pressed ? 0.8 : 1})`
  });
  const onMouseEnter = () => setHovering(true);
  const onMouseLeave = () => {
    setHovering(false);
    setPressed(false);
  };
  const onMouseDown = () => setPressed(true);
  const onMouseUp = () => setPressed(false);

  let className = "huggable";

  if (pressed) {
    className += " hugging-cursor";
  } else if (hovering) {
    className += " huggable-cursor";
  }

  return (
    <animated.div
      className={className}
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
      onMouseDown={onMouseDown}
      onMouseUp={onMouseUp}
      style={animationProps}
			role="button"
    >
      Hug me!
    </animated.div>
  );
};

export default Huggable;
```

There are a few things going on here so we'll take a closer look:

```jsx
const [hovering, setHovering] = useState(false);
const [pressed, setPressed] = useState(false);
```

There are two states that we want to track here, is the user hovering and have they pressed the button.

```jsx
const animationProps = useSpring({
  transform: `scale(${pressed ? 0.8 : 1})`
});
```

We take advantage of react-spring's `useSpring` hook to create an animation. We could also use CSS transforms here but react-spring does a lot of math for us to give us really good looking animations without much work.

```jsx
const onMouseEnter = () => setHovering(true);
const onMouseLeave = () => {
  setHovering(false);
  setPressed(false);
};
const onMouseDown = () => setPressed(true);
const onMouseUp = () => setPressed(false);
```

These event handlers will be used to manage our hovering / pressed state, which in turn will drive our behavior.

```jsx
let className = "huggable";

if (pressed) {
  className += " hugging-cursor";
} else if (hovering) {
  className += " huggable-cursor";
}
```

We set a `className` here dynamically based on our pressed / hovering state. This is used to control some basic styles as well as custom cursors when hovering. This might have been a little easier had I used JSS or styled components, but this served my needs just fine and will hopefully make sense to a wider audience.

```jsx
return (
    <animated.div
      className={className}
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
      onMouseDown={onMouseDown}
      onMouseUp={onMouseUp}
      style={animationProps}
			role="button"
    >
      Hug me!
    </animated.div>
  );
```

Finally, our markup. Not much to see here as we're just passing down the props we defined above, but it's worth pointing out the `animated` tag, which is required by react-spring.

Here's what we've got so far:

![huggable animation in action](https://dev-to-uploads.s3.amazonaws.com/i/mw0ig2iaui2qbl7xvtep.gif)

Not bad! Now let's try and isolate what we want to encapsulate in a hook. We know this should be applicable to any element, so we won't want to use any of the markup. That leaves the state management, event handlers, the animation, and our classes:

```jsx
const [hovering, setHovering] = useState(false);
const [pressed, setPressed] = useState(false);
const animationProps = useSpring({
  transform: `scale(${pressed ? 0.8 : 1})`
});
const onMouseEnter = () => setHovering(true);
const onMouseLeave = () => {
  setHovering(false);
  setPressed(false);
};
const onMouseDown = () => setPressed(true);
const onMouseUp = () => setPressed(false);

let className = "huggable";

if (pressed) {
  className += " hugging-cursor";
} else if (hovering) {
  className += " huggable-cursor";
}
```

If we copy that into it's own function it looks something like this:

```jsx
const useHug = () => {
  const [hovering, setHovering] = useState(false);
  const [pressed, setPressed] = useState(false);
  const style = useSpring({
    transform: `scale(${pressed ? 0.8 : 1})`
  });
  const onMouseEnter = () => setHovering(true);
  const onMouseLeave = () => {
    setHovering(false);
    setPressed(false);
  };
  const onMouseDown = () => setPressed(true);
  const onMouseUp = () => setPressed(false);

  let className = "";

  if (pressed) {
    className += "hugging-cursor";
  } else if (hovering) {
    className += "huggable-cursor";
  }

  //TODO: return...?
};
```

All that's left now is what we want to return. This is an important decision as it defines what consuming components can do with our hook. In this case, I really want a consumer to be able to import the hook as one object and spread it over an html element, like so:

```jsx
const huggableProps = useHug();

return <a href="/contact" {...huggableProps}>Contact Us</a>
```

This makes our hook easy to consume and use while keeping some flexibility in case an element wants to pick and choose what events to use. In order to do that we have to leave off our state variables, since they aren't valid properties for html elements. This is what our return statement winds up looking like:

```jsx
return {
  onMouseDown,
  onMouseEnter,
  onMouseLeave,
  onMouseUp,
  className,
  style
};
```

Now that we've got our hook, the only thing left to do is to use it:

```jsx
export default function App() {
  const { className, ...hugProps } = useHug();
  const buttonHugProps = useHug();
  return (
    <div className="App">
      <animated.section className={`huggable ${className}`} {...hugProps}>
        I like hugs!
      </animated.section>

      <br />
      <br />
      <animated.button {...buttonHugProps} type="button">
        buttons need hugs too
      </animated.button>
    </div>
  );
}
```

In the above example we've implemented our `useHug` hook in two ways, by taking all of the props and spreading them out over an element, and another by separating out the `className` prop and using that to compose a css class with our consuming element's existing className. We also make use of the `animated` tag to ensure our app animates correctly with react-spring.

Although this example may seem kind of silly, a lot of the process for extracting logic into a custom hook would remain the same, no matter what you're building. As you identify patterns in your code it's a good practice to look for ways you can abstract application logic or behavior in the same way you would abstract a common UI element like a modal or input. This approach can help set you up for success as your application grows over time and prevent future developers (or future you) from reinventing the wheel on something you've already implemented a few times.

If you'd like to see the full code, [here it is on codesandbox](https://codesandbox.io/s/huggable-qt088?file=/src/App.js). Feel free to fork it and play around, I'd love to see what you come up with!