Custom hooks are JavaScript functions that use other hooks. They help share stateful logic that we may otherwise need to reuse throughout our application. For example, we may create custom hooks for commonly used effects such as form handling, animations, timers, etc.

As a convention, custom hooks should have names that start with use. Additionally, they should also follow the rules of hooks. Otherwise, they don’t need to have a specific design — the developer gets to decide what arguments it takes, and if it should return anything. Consider this example useToggle():

// useToggle.js export const useToggle = (initialState = false) => { // Use the `initialState` argument to initialize the state const [state, setState] = useState(initialState); // Perform an animation each time the state changes useEffect(() => { performToggleAnimation(state); }, [state]) // Create an easy-to-use toggle function const toggle = () => { setState(state => !state) } // Return the state value and the toggle function return [state, toggle] }

In this example, we create a custom hook called useToggle() that:

  • uses useState() to manage a toggle state value
  • uses useEffect to run a toggling animation effect
  • creates a toggle() function to interact with the setState() function

We can imagine this toggling feature being used in many places in our application. Instead of copy-pasting all of this logic each time we want to use it, we can just import and use useToggle()!

import { useToggle } from './useToggle'; const DarkMode = () => { // Get the state and toggle function from useToggle() // We'll use an initial value of true const [state, toggle] = useToggle(true); return ( <button onClick={toggle}> {state ? 'On' : 'Off'} </button> ) }

In this example, we create a DarkMode component using the useToggle() custom hook. useToggle() returns the toggle’s state value and a toggle() function for switching the toggle. Now, DarkMode can use these values, and the underlying logic that supports them, without having to write out all of the code again!

Custom hooks present a number of advantages when used properly in an application:

  • They allow us to abstract our code, hide complex logic, as well as share stateful logic between multiple components.
  • When using a custom hook in two or more components, all state and effects inside are fully isolated. This is true of useState() and useEffect() as well! This means that any data from one component won’t “bleed over” into another.
  • By creating a separate file from which we export the custom hook, we can import it into any part of our application.

When used effectively, custom hooks make our code more reusable, readable, and faster to develop!


For this exercise, we’ll take a look at another example of a custom hook. In the next exercise, we’ll practice implementing one of our own.

First, in useCounter.js, review how the custom hook is written, as well as exported. Putting our custom hooks in separate files under a hooks folder is the standard approach for consolidation and file structure organization.

In Counter.js look at how we are importing the hook into our application.

Finally, in OldCounter.js look at how the component needed to be written with all of the hook logic embedded inside. Not only does it unecessarily complicate the Counter component, it also means that we can’t use that counting logic anywhere else in our application.

Sign up to start coding

Mini Info Outline Icon
By signing up for Codecademy, you agree to Codecademy's Terms of Service & Privacy Policy.

Or sign up using:

Already have an account?