skies.dev

When to Create Custom React Hooks

4 min read

If you're familiar with React, you probably have heard about React hooks, which are nothing more than functions used to supply a value, side effect, or both, within a React component.

Here's a silly example showing a counter, which alerts the user after they've reached a certain threshold.

function Counter() {
  // `useState` provides a value
  const [count, setCount] = React.useState(0);

  // `useEffect` provides a side effect
  React.useEffect(() => {
    if (count === 10) {
      window.alert('you have counted to 10! great job!');
    } else if (count >= 100) {
      window.alert('ok maybe you should get on with your day now');
    }
  }, [count]);

  return <button onClick={() => setCount(() => count + 1)}>{count}</button>;
}

Here's how you could refactor this to use a custom hook useCounter.

function useCounter() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    if (count === 10) {
      window.alert('you have counted to 10! great job!');
    } else if (count >= 100) {
      window.alert('ok maybe you should get on with your day now');
    }
  }, [count]);

  return {
    count,
    increment: () => setCount(() => count + 1),
  };
}

function Counter() {
  const {count, increment} = useCounter();
  return <button onClick={increment}>{count}</button>;
}

You can take it a step further and move the logic in useEffect to yet another hook.

function useAlertOnCountThreshold(count) {
  React.useEffect(() => {
    if (count === 10) {
      window.alert('you have counted to 10! great job!');
    } else if (count >= 100) {
      window.alert('ok maybe you should get on with your day now');
    }
  }, [count]);
}

function useCounter() {
  const [count, setCount] = React.useState(0);
  useAlertOnCountThreshold(count);
  return {
    count,
    increment: () => setCount(() => count + 1),
  };
}

function Counter() {
  const {count, increment} = useCounter();
  return <button onClick={increment}>{count}</button>;
}

Hopefully you're starting to see how custom hooks can be made using other React hooks (e.g. useState, useEffect, etc) as building blocks.

Some people think all hooks should be custom hooks. I personally disagree with this approach. I find too many levels of indirection can often be cumbersome and confusing.

In my own project, I probably wouldn't have created the useAlertOnCountThreshold hook in the previous example. That was just to demonstrate how it could be done.

The decision to create a custom hook is

  • sometimes a style preference, like what we saw in the previous example,
  • and sometimes a necessity in order to reuse functionality. We saw this building the notification state management library.

When you're faced with a choice of optionally creating a custom hook (i.e. to make a code style decision), go with the approach that's consistent with your team's style guide. If you're working alone, go with the approach you find makes the most sense.

A common mistake when beginning to write custom hooks is to make things hooks that should really be regular JavaScript functions.

If you're function is dealing with React state using useState, useEffect, etc, then use a custom hook. Name the function with the use prefix e.g. useSession, useModal, useThing, etc.

Otherwise, just make a normal JavaScript function.

Summary

  • Create a custom hooks to wrap logic that utilizes the standard hooks (e.g. useState, useEffect, etc). If your function is not working with React state, you want a normal function, not a React hook.
  • Create a custom hook if it makes the code easier to maintain. For example, useEffect hooks with many lines of business logic can quickly make a component hard to work with. Often, extracting out logic into a custom hook can help.
  • Create a custom hook if it will be reused in many places. This case often comes up when using the Context API. We saw this when we built a notification state management library.
  • Avoid creating a custom hook if the business logic is simple enough. In the earlier example, I wouldn't make the custom hook useAlertOnCountThreshold since it's so simple, but that's personal preference. I made the custom hook to show how you could make a custom hook there.

(clap if you liked the article)

You might also like