← Back to React Course | Chapter 6: Custom Hooks & Advanced Patterns | Lesson 1 of 10

Building Your First Custom Hook

A custom hook is like writing your own recipe once so you can reuse it in any dish instead of writing the same steps over and over.
Syntax
markup
function useHookName(parameter) {
  const [state, setState] = useState(parameter);
  // shared stateful logic
  return { state, setState };
}

const { state } = useHookName(argument);

What Problem Custom Hooks Solve

When two different components need the same piece of stateful logic, like tracking window size or a counter, copying that logic into both components duplicates code and makes updates error-prone.

A custom hook lets you write that logic once as a reusable function. Any component can then call it to get the same behavior.

Note: If you find yourself copying a useState+useEffect pair into a second component, that's usually a sign it should become a custom hook.
Warning: A custom hook shares its LOGIC, not its STATE — two components calling the same custom hook still get independent, separate state.

Example: What Problem Custom Hooks Solve

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
function useCounter(start) {
  const [count, setCount] = React.useState(start);
  const increment = () => setCount(c => c + 1);
  return { count, increment };
}
function App() {
  const { count, increment } = useCounter(0);
  return <button onClick={increment}>Count: {count}</button>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>

The 'use' Naming Convention

A custom hook's name must start with lowercase use, like useCounter or useFetch. This isn't just a style choice — React's linter and the rules-of-hooks system use this prefix to know a function is allowed to call other hooks inside it.

A regular helper function without the use prefix cannot call useState or useEffect safely.

Note: Name your hook after what it returns or does, like useWindowWidth or useOnlineStatus, so it's self-documenting.
Warning: Naming a function useHelper() when it doesn't actually call any hooks is misleading — only name it 'use...' if it genuinely uses hooks internally.

Example: The 'use' Naming Convention

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
function useToggleValue(initial) {
  const [value, setValue] = React.useState(initial);
  const toggle = () => setValue(v => !v);
  return [value, toggle];
}
function App() {
  const [isOn, toggle] = useToggleValue(false);
  return <button onClick={toggle}>{isOn ? "ON" : "OFF"}</button>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>

Building Your First Custom Hook

To build a custom hook, write a normal JavaScript function, call one or more built-in hooks inside it, and return whatever data or functions the calling component needs.

This example builds useWindowWidth, which tracks the browser window's width and updates automatically on resize.

Note: Return an array (like useState does) when order matters, or an object when you want named, self-documenting values.
Warning: Always clean up any event listeners you add inside a custom hook's useEffect, or they'll pile up every time the component re-renders.

Example: Building Your First Custom Hook

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
function useWindowWidth() {
  const [width, setWidth] = React.useState(window.innerWidth);
  React.useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);
  return width;
}
function App() {
  const width = useWindowWidth();
  return <p>Window width: {width}px</p>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Forgetting to prefix the function name with use, which breaks React's rules-of-hooks linting and hook detection.
  2. Copy-pasting the same useState+useEffect logic into multiple components instead of extracting it into a custom hook.
  3. Calling a custom hook conditionally (inside an if-statement), which violates the same rules that apply to built-in hooks.
Chapter Summary
  • A custom hook is a JavaScript function whose name starts with use and that calls other hooks inside it.
  • Custom hooks let you extract and reuse stateful logic across multiple components.
  • They follow the same rules of hooks as built-in hooks (top-level calls only, no conditionals).
  • Each component that uses a custom hook gets its own independent state, not a shared one.
Browser Support

Available since React 16.8 (Hooks introduction) — custom hooks are just plain functions built on top of built-in hooks.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.