Introduction to Custom React Hooks
Tags: react, javascript, webdev
Published: 2020-03-27 01:27:27

---
title: Introduction to Custom React Hooks
published: true
date: 2020-03-26 13:00:00 UTC
tags: react, javascript, webdev
canonical_url: https://nimblewebdeveloper.com/blog/introduction-to-custom-react-hooks
cover_image: 
---

## How to write custom React hooks

If you've been around the the React world lately, you'll no doubt have noticed or used hooks. Hooks were introduced into React in 16.8 and were kinda a big deal.

<img src="https://cdn.sanity.io/images/uvwftosn/production/43ae42b8e424462c68878651a9cf7573b5a8c095-500x246.png" alt="Ron Burgundy saying "I dont know how to put this but Im kind of a big deal""/>

React hooks gave us the ability to have state in function components, reduce the need for render props, and just generally make DX and life better.

As always, [the React docs](https://reactjs.org/docs/hooks-intro.html) are a good place to start on this, so I recommend checking them out too.

Custom hooks in React are a way to reuse functionality (particularly functionality involving stateful logic) between components. You could just use a function to share between components, but then you don't get all the goodness of being able to access component lifecycle events and state. React hooks let you 'hook' (see, it's in the name) into things like component lifecycle (mount, unmount, etc), state, and other hooks.

So what is a custom hook, and how is it different to just a function? Well, a custom hook is just a function that uses other hooks. These might be other custom hooks, or React's basic hooks (useState, useEffect, etc). If you don't use any hooks, you've just got a function, not a hook.

The convention for naming hooks is to prefix your function with "use" (as in "useState", "useEffect" etc). For example if I were to create a custom hook to use the scroll distance down the page, I might name it "useScrollDistance". This is by no means a rule, and your hook will still work if you name it "myCoolHook", but it's a useful convention allows others to easily recognise your function as a hook.

## Custom hook example

To help explain how custom hooks work, I'm going to show you a quick example of hook that you might even use in a real app (in fact it's in the codebase of one of mine). We'll make a hook that let's us keep track of the scroll distance down a page.

### Quick react hook recap

First, we'll just take a quick recap of how react hooks work; we'll use **useState** and **useEffect** as examples.

If we have a simple component, which needs some state, we can use **useState** to keep track of it like this;

```jsx  
import React, {useState} from 'react'  
  
const myComponent = () => {  
    
  //This is our hook call to useState  
  // useState will return an array [stateValue, stateSetter]  
  // useState can also take the initial state as an argument (0)  
  const [counterValue, setCounterValue] = useState(0);  
    
  const incrementCounter = () => {  
    setCounterValue(counterValue+1);  
  }  
    
  return (<div>  
    <p>Counter Value: {counterValue}</p>  
    <div>  
      <button onClick={incrementCounter}>Increment Counter</button>  
    </div>  
  </div>);  
}  
  
```

Here we have a simple component which calls **useState** , with the argument 0. This returns an array containing the state variable, and a function to update that state variable. The argument 0 is the initial value we would like to store in the state variable.

Ok, lets say we'd like to know when the **counterValue** has changed, and trigger some action, a side-effect. We can do that with the **useEffect** hook. useEffect will subscribe to changes in the variable you specify.

```jsx 
import React, {useState, useEffect} from 'react'  
  
const myComponent = () => {  
    
  //This is our hook call to useState  
  // useState will return an array [stateValue, stateSetter]  
  // useState can also take the initial state as an argument (0)  
  const [counterValue, setCounterValue] = useState(0);  
    
  const incrementCounter = () => {  
    setCounterValue(counterValue+1);  
  }  
    
  // Using the useEffect hook  
  // The first argument is the callback to trigger  
  // when the value changes  
  // The second argument is the variable we'd like to track  
  useEffect(() => {  
    console.log(`The new counter value is: ${counterValue}`)  
  }, [counterValue]);  
    
  return (  
    <div>  
      <p>Counter Value: {counterValue}</p>  
      <div>  
        <button onClick={incrementCounter}>Increment Counter</button>  
      </div>  
    </div>  
  );  
}  
  
```

Now we've modified the component to log the value of the counter every time it changes. This isn't a particularly useful real-world scenario, but hopefully it demonstrates how the hook works.

We added a call to **useEffect** and passed it a callback to run every time the variable we're interested in changes. In the second argument, we passed in an array of the variables we'd like to keep track of.

### A really simple custom hook

Using the example above, let's say we wanted to reuse this functionality (logging a state variable) in multiple places. I can't see why, but bear with me.

What we can do is compose a custom hook from our basic useState and useEffect hooks and make it reusable.

```jsx  
import React, {useState,useEffect} from 'react';  
  
  
//This is our custom hook  
//it abstracts the logic & state of our counter  
const useCounterValue = (initialValue=0) => {  
    
  // Set up the state, same as before  
  const [counterValue, setCounterValue] = useState(initialValue);  
    
  // Create our count increment function  
  const incrementCounter = () => {  
    setCounterValue(counterValue+1);  
  }  
    
  // Watch for changes in the value  
  useEffect(() => {  
    console.log(`The new counter value is ${counterValue}`);  
  }, [counterValue])  
    
  // Return the state variable and our  
  // increment function  
  return [counterValue, incrementCounter];  
}  
  
const myComponent = () => {  
  // Use our custom hook  
  const [counterValue, incrementCounter] = useCounterValue(0);  
    
  return (  
    <div>  
      <p>Counter Value: {counterValue}</p>  
      <div>  
        <button onClick={incrementCounter}>Increment Counter</button>  
      </div>  
    </div>  
  );  
}  
  
```

Here we created a custom hook **useCounterValue** which does exactly the same thing as our previous component, but now it's reusable. We could add this code into multiple components and consume it anywhere .

( **BIG** note: the state won't be shared simultaneously. The state is specific to the component you're using the hook in!)

I know this example is a bit contrived, but hopefully it demonstrates some of the power and simplicity of custom hooks!

## A real example

Ok, now we're going to make a real custom React hook, one that would actually be useful!

We'll make a custom hook called **useScrollDistance** which will tell us how far down the page the user has scrolled. Examples of use cases for this might include; "polyfilling" position: sticky, infinite loaders, animation triggers etc. You could even adapt this to know how far a different scrollable element has been scrolled (think; fullpage style transitions etc).

I think I've wasted enough of your time already, so let's just do it. Here's our custom hook;

```jsx  
// useScrollDistance.js  
  
import {useState, useEffect} from 'react';  
  
const useScrollDistance = () => {  
  //Set up a state variable and  
  // store the initial value of window.scrollY  
  const [scrollDistance, setScrollDistance] = useState(window.scrollY);  
    
  //Set up a handler to update our state variable  
  //on scroll events  
  const onScrollHandler = () => {  
    setScrollDistance(window.scrollY);  
  }  
    
  //call useEffect to listen to component mount & unmount  
  useEffect(() => {  
    //Add a javascript event listener to the window  
    //to listen to scroll events  
    window.addEventListener('scroll', onScrollHandler);  
      
    //Return a function to run on unmount  
    return () => {  
      //Don't forget to remove any event listeners on unmount!  
      window.removeEventListener('scroll', onScrollHandler);  
    }  
  }, []);  
    
  //Finally return the value of interest  
  return scrollDistance;  
}  
  
export default useScrollDistance;  
  
```

That's our hook, it uses useEffect to run a function on component mount which binds an event listener to the window's scroll event. Our event handler then updates our state with the new value of the scroll distance.

And here's how we might use it;

```jsx  
  
//Import our custom hook  
import useScrollDistance from './useScrollDistance'  
  
const myComponent = () => {  
  //Call our hook  
  const scrollDistance = useScrollDistance();  
    
  //Render the value  
  return (  
    <p>Scroll distance: {scrollDistance}</p>  
  );  
}  
  
```

And this is what that might look like (with a little styling applied)

<img src="https://cdn.sanity.io/images/uvwftosn/production/b6c5dc1a8a8578cdf8a33e482b5bb4da241e853c-974x538.gif" alt="null"/>

You probably wouldn't want to just slap this code into production as is. For one, you might want to add some throttling to the event listener (see my post about understanding throttling, or my post about using custom hooks to listen to DOM events for an example).

## Your turn

Hopefully this has shown you how easy it is to create custom hooks, and how useful and powerful they can be. Check out my other posts on the topic for a bit more info if you're interested.

- Understanding event throttling
- Using custom React hooks to listen to DOM events

Anything a bit vague? Need more info? Let me know! Hit me up [on twitter @baffledbasti](https://twitter.com/baffledbasti).