Back to top

Pegah Eizadkhah

Pegah is a full stack developer at Detroit Labs with over three years of experience building scalable and maintainable applications. When she is not honing her coding skills, she is probably running. She enjoys racing, traveling, or racing while traveling.

Why and When To Use Custom Hooks

The main reason to write a custom hook is for code reusability. For example, instead of writing the same code across multiple components that use the same common stateful logic (say a “setState” or localStorage logic), you can put that code inside a custom hook and reuse it.

Consider the example below:

I want to use the data that Strava provides for my run workouts in my third-party application. Through the Strava API I can get activity info like route map, distance, achievements, and any other info that Strava provides. Let’s say I have a component that displays my past 10 activities. Here’s what that component will look like:

How To Use Custom Hooks

Now let’s say in this app we have multiple components that use the activities data. These components will have the loading state and the activities state in common. Here’s where we want to extract the shared state and the shared useEffect fetch hook into our own custom hook so we don’t repeat it. This is what that custom hook will look like:

And then we can call the hook from our component like this:

This way we can keep our components as simple as possible and isolate the testable logic in a custom hook function, as well as making shared logic between components reusable.

Something to note: there is a naming convention for custom hooks! React linting plugin requires that we use the naming convention – “use[something]” (in our example, useActivitiesData) in order to find bugs. By keeping things consistent, it becomes a lot easier to flag programming errors, stylistic errors, and error-prone constructs.

Finally, since the introduction of hooks, lots of custom hooks libraries have been added for common front-end scenarios such as using localstorage, memoization, or routing (useLocalStorage, useMemoCompare, and useRoutes are some examples), so we don’t have to worry about reinventing the wheel in most situations. Here’s a nice resource to browse some of those examples: