Hooks vs Class Lifecycle Methods
In this page:
State: this.state vs useState
A class component stores state as an object on this.state and updates it via this.setState(), which merges the given fields into the existing state object. useState instead gives you one independent state variable and setter pair per call, and does NOT automatically merge objects.
Note: If you're translating class code to Hooks, remember each this.state field often becomes its own separate useState call.
Warning: Unlike this.setState, calling a useState setter with an object REPLACES the whole value -- it does not merge it with the previous object automatically.
Example: State: this.state vs useState
<!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">
// Hooks version
function Counter() {
const [count, setCount] = React.useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<Counter />);
</script>
</body>
</html>
Lifecycle Methods vs useEffect
Class components split side-effect logic across several lifecycle methods: componentDidMount (runs once), componentDidUpdate (runs on updates), and componentWillUnmount (runs on removal). useEffect combines all three roles into one Hook, distinguished by its dependency array and optional cleanup function.
Note: An effect with [] roughly matches componentDidMount + componentWillUnmount combined; an effect with dependencies roughly matches componentDidUpdate too.
Warning: The match between useEffect and lifecycle methods is close but not perfect -- effect timing (after paint) differs slightly from componentDidMount's timing.
Example: Lifecycle Methods vs useEffect
<!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 MountLogger() {
React.useEffect(() => {
console.log("Like componentDidMount");
return () => console.log("Like componentWillUnmount");
}, []);
return <p>Check the console.</p>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<MountLogger />);
</script>
</body>
</html>
Why Function Components Are Now Preferred
Hooks let function components do everything class components can, with less boilerplate (no constructor, no this binding issues) and easier logic reuse via custom Hooks. Because of this, the official React docs and most new projects favor function components with Hooks over classes.
Note: When starting a new React project today, default to function components with Hooks -- reserve class components only for maintaining existing legacy code.
Warning: this binding issues (like event handlers losing their this context) are a common class-component pitfall that Hooks avoid entirely.
Example: Why Function Components Are Now Preferred
<!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 ModernComponent() {
const [liked, setLiked] = React.useState(false);
return <button onClick={() => setLiked(!liked)}>{liked ? "Liked!" : "Like"}</button>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<ModernComponent />);
</script>
</body>
</html>
- Assuming Hooks and class lifecycle methods map one-to-one in every detail -- some behaviors (like effect timing) differ subtly.
- Mixing class-based patterns (like
this.state) into a function component by mistake. - Believing class components are deprecated or unsupported -- they still work fine, just aren't the recommended style for new code.
- Hooks let function components use state and other React features previously only available in classes.
- useState replaces
this.state/this.setState. - useEffect replaces most uses of componentDidMount, componentDidUpdate, and componentWillUnmount combined.
- Function components with Hooks are now the recommended default in React.
Hooks were introduced in React 16.8; class components remain fully supported in React 18.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: