Suggest an editImprove this articleRefine the answer for “Custom hooks”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)A **custom hook** is a regular JS function whose name starts with `use`, and which uses other React hooks (`useState`, `useEffect`, etc.) inside it. **Key point:** it exists to extract and reuse logic (state, effects, subscriptions) without duplicating it across components.Shown above the full answer for quick recall.Answer (EN)Image## What a custom hook is A **custom hook** is a regular JS function whose name starts with `use`, and which uses other React hooks (`useState`, `useEffect`, etc.) inside it. It exists to **extract and reuse logic** (state, effects, subscriptions), without duplicating it across components. > The idea: "share **behavior**, not markup". The component stays clean, the UI stays separate. --- ## How to build one (micro-examples) #### 1) Basic: `useToggle` ```javascript import { useState, useCallback } from "react"; export function useToggle(initial = false) { const [on, setOn] = useState(initial); const toggle = useCallback(() => setOn(v => !v), []); const setTrue = useCallback(() => setOn(true), []); const setFalse = useCallback(() => setOn(false), []); return { on, toggle, setTrue, setFalse }; } ``` #### 2) With a side effect and cleanup: `useDebounce` ```javascript import { useEffect, useState } from "react"; export function useDebounce(value, delay = 300) { const [debounced, setDebounced] = useState(value); useEffect(() => { const id = setTimeout(() => setDebounced(value), delay); return () => clearTimeout(id); // cleanup }, [value, delay]); return debounced; } ``` #### 3) With local storage: `useLocalStorage` ```javascript import { useEffect, useState } from "react"; export function useLocalStorage(key, initial) { const [state, setState] = useState(() => { const raw = localStorage.getItem(key); return raw != null ? JSON.parse(raw) : initial; }); useEffect(() => { localStorage.setItem(key, JSON.stringify(state)); }, [key, state]); return [state, setState]; // a familiar interface, like useState } ``` --- ## The rules (restrictions) of hooks - must know 1. **A name starting with** `use` The function must be called `useSomething`. This is not "magic", it is a convention that the linter checks. 2. **Only call hooks at the top level** Not inside conditions, loops, or nested functions. The order of calls must be **the same on every render**. ```javascript // bad if (cond) { useEffect(...); } // good useEffect(() => { if (cond) {/*...*/} }, [cond]); ``` 3. **Only call hooks from React functions** From function components or other hooks. Not from regular functions, not from event handlers, not from classes. 4. **Custom hooks are synchronous functions** The hook itself must not be `async`. Asynchrony belongs **inside the effects**. 5. **Follow** `exhaustive-deps` The dependencies of effects/memoizations must be correct. Use `eslint-plugin-react-hooks` to enforce this. 6. **Do not mix responsibilities** A hook is about **one** task (fetching, toggling, forms, syncing with storage, and so on). Small, composable hooks are better than one "giga-hook". 7. **Stable references outward** If the hook returns functions/objects, memoize them (`useCallback`/`useMemo`) so consumers do not re-render unnecessarily. 8. **It does not render UI** The hook returns **data/methods**, not JSX. Drawing is the component's job. 9. **SSR specifics** Anything that depends on `window/document/localStorage` should be checked inside effects or conditionally (these APIs do not exist on the server). --- ## When to build a custom hook - You are repeating the same `useEffect + useState` in several components. - You need to encapsulate complex logic (forms, requests, web sockets, URL↔state sync). - You want to provide a **clean, testable API** for the behavior. --- ## Recommendations for hook APIs - **Return a primitive, predictable contract** (an array like `useState`, or an object with named fields). - **Document the dependencies** (what you pass into the hook, what it returns). - **Minimize outside effects**: keep anything with side effects inside `useEffect` with careful `cleanup`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.