Implementing React Custom Hooks: A Complete Guide
Tags: webdev, react
Published: 2022-04-05 12:38:17

---
title: Implementing React Custom Hooks: A Complete Guide
published: true
date: 2022-04-05 10:30:25 UTC
tags: webdev, react, 
canonical_url: https://www.syncfusion.com/blogs/post/implementing-react-custom-hooks-a-complete-guide.aspx
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7rdtjlzlieujn48eip7n.png
---

React Hooks are functions that allow you to use state and life-cycle features from function components. If you’ve been using React, you’ve probably used their built-in Hooks, such as **useState, useEffect,** and **useContext.** However, React does not limit you to using only those Hooks.

Creating your own Hooks in React can be useful in various situations. Custom Hooks are an excellent way to share logic between components and improve your component tree’s readability.

This article explains how to implement various custom Hooks in React. Let’s get started.

## Implementing a custom Hook

A custom Hook is a JavaScript function that begins with **use.** It is not mandatory to begin the custom Hook name with “use,” but without it, React would be unable to check for violations of the [Hooks rules](https://reactjs.org/docs/hooks-rules.html "Rules of Hooks documentation") automatically. Therefore, it is critical to adhere to that naming convention.

Consider the following example of defining a custom Hook called **useFriendStatus.**

```js
import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {  
  const \[isOnline, setIsOnline\] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}
```

In the above example, we call the **useState** and **useEffect** Hooks unconditionally at the top level of our custom Hook, just as we would in a component. The **useFriendStatus** Hook’s purpose is to subscribe us to a friend’s status. As a result, it accepts a **friendID** as an argument and returns whether the friend is online.

If we didn’t define the **useFriendStatus** custom Hook, we’d have to write the logic inside this Hook in every component to subscribe to a friend’s status. So, instead of duplicating code, we can use this custom Hook.

Now, let’s look at how we can put this custom Hook to use.

```js
function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
export default FriendStatus;
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}
export default FriendListItem;
```

In the above example, you can see that the **useFriendStatus** Hook is used in two different functional components, **FriendStatus** and **FriendListItem.** You can even use the same custom Hook twice within the same component.

**Note:** The state is not shared between two components that use the same Hook.

## Passing information between Hooks

Since Hooks are a type of function, we can pass data between them. Consider the following example where a user can select any friend and see whether that friend is online.

```js
const friendList = \[
  { id: 1, name: 'John' },
  { id: 2, name: 'Michael' },
  { id: 3, name: 'Mary' },
\];

function ChatRecipientPicker() {
  const \[recipientID, setRecipientID\] = useState(1);  
  const isRecipientOnline = useFriendStatus(recipientID);
  return (
    <>
      <Circle color={isRecipientOnline ? 'green' : 'red'} />
      <select
        value={recipientID}
        onChange={e => setRecipientID(Number(e.target.value))}
      >
        {friendList.map(friend => (
          <option key={friend.id} value={friend.id}>
            {friend.name}
          </option>
        ))}
      </select>
    </>
  );
}
```

Here, the **recipientID** state variable value is passed as an argument to the custom **useFriendStatus** Hook. When the user selects a different friend in the **<select>** picker, we use the **useState** Hook to update the **recipientID.** The useFriendStatus Hook then unsubscribes from the previously selected friend and subscribes to the newly selected friend’s status.

## Custom Hooks examples

Now that you have an understanding of how custom Hooks work, let’s look at several scenarios for creating custom Hooks.

### useLocalStorage

To use local storage in React, we can construct a custom Hook. The Hook allows you to preserve data in the browser as key-value pairs for later use.

```js
import { useState } from "react";
export default function App() {
  // Usage
  const \[name, setName\] = useLocalStorage("name", "John");
  return (
    <div>
      <input
        type="text"
        placeholder="Enter your name"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
    </div>
  );
}
// Hook
function useLocalStorage(key, initialValue) {
  const \[storedValue, setStoredValue\] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.log(error);
      return initialValue;
    }
  });
const setValue = (value) => {
    try {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key,JSON.stringify(valueToStore));
    } catch (error) {
      console.log(error);
    }
  };
  return \[storedValue, setValue\];
}
```

### useToggle

This is a simple but helpful custom Hook that can be used effectively in many web applications. The **useToggle** Hook allows you to take a true or false value and convert it to the inverse. It can be used to toggle modals and menus.

```js
import { useCallback, useState } from 'react';
export default function App() {
    // Usage
    const \[isModalOpen, setIsModalOpen\] = useToggle();
    return (
        <button onClick={setIsModalOpen}>
          {isModalOpen ? 'Close Modal' : 'Open Modal'} 
        </button>
    );
}
// Hook
const useToggle = (initialState = false) => {
    const \[state, setState\] = useState(initialState);
    const toggle = useCallback(() => setState(state => !state), \[\]);
    return \[state, toggle\]
}
```

### useEventListener

You may find yourself adding a lot of event listeners using **useEffect** in your code. In such situations, you should move that logic to a custom Hook. The **useEventListener** Hook first ensures that the element supports the **addEventListener** method, and then it creates and adds an event listener. If **eventName** or **element** changes, the Hook will rerun.

```js
import { useState, useRef, useEffect, useCallback } from "react";
export default function App() {
  const \[coords, setCoords\] = useState({ x: 0, y: 0 });
  const handler = useCallback(
    ({ clientX, clientY }) => {
      setCoords({ x: clientX, y: clientY });
    },
    \[setCoords\]
  );
  // Usage
  useEventListener('mousemove', handler);
return (
    <h1>
      The mouse position is ({coords.x}, {coords.y})
    </h1>
  );
}
// Hook
function useEventListener(eventName, handler, element = window) {
  const savedHandler = useRef();
  useEffect(() => {
    savedHandler.current = handler;
  }, \[handler\]);
  useEffect(
    () => {
      const isSupported = element && element.addEventListener;
      if (!isSupported) return;
      const eventListener = event => savedHandler.current(event);
      element.addEventListener(eventName, eventListener);
      return () => {
        element.removeEventListener(eventName, eventListener);
      };
    },
    \[eventName, element\]
  );
}
```

Similarly, you can write custom Hooks to handle various use cases, such as form handling, animation, timers, and many others.

## Advantages of custom Hooks

The main advantage of React Hooks is the reusability of stateful logic. In addition, custom Hooks can be easily shared with other components without changing the component hierarchy. Also, we don’t have to be concerned about the **this** keyword when using Hooks.

Compared to HOCs, the custom Hooks approach provides cleaner logic and a better understanding of the relationship between the data and the component. As a result, it’s easier to read and has fewer lines of code.

We can write separate unit tests for custom Hooks, making testing easier. It is also easier to test components with multiple custom Hooks using the [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/ "React Testing Library documentation").

## Conclusion

Custom Hooks enable exceptional flexibility in sharing logic previously unavailable in React components. I hope this guide has given you a better understanding of creating your own React Hooks.

Thank you for reading.

The [Syncfusion React JS](https://www.syncfusion.com/react-ui-components "React UI components") suite offers over 65 high-performance, lightweight, modular, and responsive UI components in a single package. This library is the only suite you’ll ever need to construct a complete application.

If you have any questions or comments, you can contact us through our [support forums](https://www.syncfusion.com/forums "Syncfusion support forum"), [support portal](https://support.syncfusion.com/ "Syncfusion support portal"), or [feedback portal](https://www.syncfusion.com/feedback/ "Syncfusion Feedback Portal"). We are always happy to assist you!

## Related blogs

- [Top 5 React Lazy-Loading Libraries for 2022](https://www.syncfusion.com/blogs/post/top-5-react-lazy-loading-libraries-for-2022.aspx "Top 5 React Lazy-Loading Libraries for 2022 blog")
- [Create Dynamic Forms in React Using React Hook Forms](https://www.syncfusion.com/blogs/post/create-dynamic-forms-in-react-using-react-hook-forms.aspx "Create Dynamic Forms in React Using React Hook Forms blog")
- [Everything You Should Know About React 18](https://www.syncfusion.com/blogs/post/everything-you-should-know-about-react-18.aspx "Everything You Should Know About React 18 blog")
- [How to Develop a Flight Tracker Application with React Gantt Chart](https://www.syncfusion.com/blogs/post/flight-tracker-application-with-react-gantt-chart.aspx "How to Develop a Flight Tracker Application with React Gantt Chart blog")