Suggest an editImprove this articleRefine the answer for “What problem do hooks solve in React?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**React hooks** solve three problems class components had: no clean way to share stateful logic between components (HOCs and render props created wrapper hell), lifecycle methods that scattered related code across `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount`, and complex `this` binding. Introduced in React 16.8, hooks handle all three through plain functions.Shown above the full answer for quick recall.Answer (EN)Image**React hooks** are functions that let function components use state, side effects, and other React features without class syntax. ## Theory ### TL;DR - Before React 16.8, only class components could have state and lifecycle methods - Sharing stateful logic between classes required HOCs or render props, creating deeply nested component trees - Lifecycle methods scattered related code: setup in `componentDidMount`, cleanup in `componentWillUnmount`, updates in `componentDidUpdate` - `this` binding in classes is a frequent source of bugs - Hooks solve all three through plain functions in any function component ### Class vs hook: side by side ```jsx // Class: setup and cleanup live in separate methods class ChatRoom extends React.Component { componentDidMount() { this.socket = openSocket(this.props.roomId); } componentWillUnmount() { this.socket.close(); } } // Hook: one effect keeps both together function ChatRoom({ roomId }) { useEffect(() => { const socket = openSocket(roomId); return () => socket.close(); // cleanup lives next to setup }, [roomId]); } ``` The class splits one concern across two methods. The hook keeps it in one place. That is the core idea. ### Why class components did not scale A class component with moderate complexity spread its logic across four locations: state in the constructor, subscriptions in `componentDidMount`, reactions to prop changes in `componentDidUpdate`, and teardown in `componentWillUnmount`. Four places, one concern. The bigger problem was reuse. If two components needed the same subscription logic, there was no clean path. Developers reached for Higher-Order Components or render props. Both patterns work. But stack a few HOCs and React DevTools shows `Connect(WithAuth(WithTheme(MyComponent)))`. That is wrapper hell. One thing I've noticed in codebases that migrated from classes: the files get shorter, but more importantly the logic becomes traceable. You read a `useEffect` and see the full lifecycle of that concern in a few lines. ### Custom hooks: where the problem actually gets solved `useState` and `useEffect` are useful, but custom hooks are the real answer to reuse. A custom hook is a function whose name starts with `use` and which calls other hooks inside. Pull your subscription logic into `useSubscription`, your form state into `useForm`, your API calls into `useFetch`. Any component can call it. No HOC, no nesting, no extra layers in the tree. ### Common mistakes **Missing the dependency array:** ```jsx useEffect(() => { fetchUser(userId); }); // runs after every render - usually a bug useEffect(() => { fetchUser(userId); }, [userId]); // runs only when userId changes ``` **Forgetting the cleanup function:** ```jsx // Bug: listener accumulates on every render useEffect(() => { window.addEventListener('keydown', handleKey); }, []); // Fix useEffect(() => { window.addEventListener('keydown', handleKey); return () => window.removeEventListener('keydown', handleKey); }, []); ``` **Reading state right after setting it:** ```jsx setCount(count + 1); console.log(count); // still old value - React batches updates ``` State updates are async. The new value is only available on the next render. ### Follow-up questions **Q:** Why can't hooks be called inside conditions or loops? **A:** React tracks hooks by call order. If a hook is skipped in one render, the order shifts and React reads wrong state for every hook after it. The rule keeps call order stable across renders. **Q:** What is a custom hook? **A:** A function starting with `use` that calls other hooks inside. It extracts stateful logic into a reusable function without adding any layers to the component tree. **Q:** What did teams use before hooks to share logic between components? **A:** Mainly HOCs and render props. Both work but wrap components in extra layers. A custom hook does the same thing with a plain function call. **Q:** Does `useEffect` with `[]` fully replace `componentDidMount`? **A:** Almost. Both run after the first render. But `useEffect` runs after the browser paints, while `componentDidMount` ran after DOM updates and before paint. For layout measurements, `useLayoutEffect` is closer to the original behavior. ## Examples ### Counter: class vs hook ```jsx // Class: constructor, bind, and this required throughout class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.increment = this.increment.bind(this); // easy to forget } increment() { this.setState({ count: this.state.count + 1 }); } render() { return <button onClick={this.increment}>{this.state.count}</button>; } } // Hook: same behavior, no ceremony function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>{count}</button>; } ``` The class needs a constructor, a `bind` call, and `this` everywhere. The function component with `useState` does the same in two lines. ### Custom hook: reusable data fetching ```jsx // Extract fetch logic once, use it in any component function useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; fetch(url) .then(res => res.json()) .then(result => { if (!cancelled) setData(result); }) .catch(err => { if (!cancelled) setError(err); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; // prevent update after unmount }, [url]); return { data, loading, error }; } // Any component gets all three states in one line function UserProfile({ userId }) { const { data: user, loading } = useFetch(`/api/users/${userId}`); if (loading) return <span>Loading...</span>; return <h1>{user.name}</h1>; } ``` The fetch logic lives once and tests once. Before hooks, teams either duplicated it in every component or wrapped it in a HOC. A custom hook does it without nesting anything.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.