My first React hook
Tags: react, hooks, javascript
Published: 2018-10-27 04:46:12

---
title: My first React hook
published: true
description: react, hooks
tags: react, hooks, javascript
---

This **is not** an introduction to hooks, or any kind of tip or best practices, at the end hooks were just announced, so we have to play around with them and wait to see how the community embrace them, and the best practices that will come up.  This is just my experience of implementing a hook.

I wanted to create a hook that will use the Intersection Observer API, to track the visibility of a functional component. Whenever the visibility change (component on viewport or not) I want the hook to update the state of the component.

I am gonna call my hook `useVisibility`. 

Intersection Observer needs access to the DOM node it's gonna observer:

```js
var target = document.querySelector('#listItem');
observer.observe(target);
```

So `useRef` seems the right hook to create a reference to our component's markup

```js
function HelloComponent(){
  const nodeRef = useRef(null);

  return (
    <div className="App" ref={nodeRef}>
      <h1>Hello</h1>
    </div>
  );
}
```

Apart from the node reference, Intersection Observer accepts some options, this can be the second parameter of our hook, so the signature of it can be:

```js
  const visibility = useVisibility(nodeRef, options); 
```

Let's write the actual hook now, we will need the `useState` hook of React to track the visibility state

```js
function useVisibility(node, options = {}) {
  const [ visible, setVisibilty ] = useState({});
  ...
```

Then we are gonna create an instance of the Intersection Observer passing a callback and the options.

```js
const observer = new IntersectionObserver(handleObserverUpdate, options);
```

To start calling the callback we need to tell the observer to start observing our node, since this is a browser API "outside of react world", we are gonna use the `useEffect` hook provided by React. 

```js
  useEffect(() => {
    if (node.current) {
      observer.observe(node.current);
    }
  });
```

Our code has a memory leak though, we need to provide a way to cleanup, for this reason we are returning a callback that when is called tells our observer to stop watching the node.

```js
  useEffect(() => {
    if (node.current) {
      observer.observe(node.current);
    }

    return function cleanup() {
      observer.unobserve(node.current);
    };
  });
```

Finally our handler will look like this:

```js
  const isIntersecting = useRef();

  const handleObserverUpdate = (entries) => {
    const ent = entries[0];

    if (isIntersecting.current !== ent.isIntersecting) {
      setVisibilty(ent);
      isIntersecting.current = ent.isIntersecting;
    }
  };
```

Now, you may wonder why I am using `const isIntersecting = useRef()` since this is not a DOM node.
 
As the docs state:

> Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.


I wanted a ref attribute that persist for the full lifetime of the component.

Summarising, personally I found the new API very simple and super useful, and I am very excited with what the solutions and best practices the community come up in the next months. 

To be honest though, testing was not as easy as expected, mainly because of the need to mock a browser API like this, and not because of the hook API. Most testing frameworks come with utils to simulate clicks, input changes etc, but some APIs need manual mocking and depending on their complexity that can be tricky.

You can find the hook [here](https://github.com/AvraamMavridis/react-intersection-visible-hook)

{% github https://github.com/AvraamMavridis/react-intersection-visible-hook %}