React useEffect vs useState
Overview
React’s useState and useEffect hooks are essential tools for managing state and side effects in functional components. However, they serve distinct purposes, and knowing when to use each—or when to avoid them entirely—can make your code cleaner and more efficient.
This guide covers:
- What
useStateanduseEffectdo - When to use
useStatevs.useEffectvs. local variables - Practical examples and decision-making workflows
- Common pitfalls and how to avoid them
- Additional resources for deeper learning
Quick Recap
What is useState?
The useState hook manages state—data that persists across renders and triggers re-renders when updated. It’s ideal for tracking component-specific data like user inputs or UI toggles.
State refers to any data that is specific to a component and can change over time. When state changes, the component will re-render to reflect the updated data.
const [count, setCount] = useState(0);
count: The current value of the state.setCount: A function to update the value ofcount.useState(0): Initializescountwith a value of0.
What is useEffect?
The useEffect hook handles side effects—operations that interact with the outside world (e.g., APIs, DOM updates) or need to run at specific lifecycle moments (mount, update, unmount).
Side effects refer to anything that happens outside of your React component that needs to be synchronized with your app. This can include fetching data, updating the DOM, or even logging.
useEffect(() => {
fetch('https://api.example.com/data')
.then(res => res.json())
.then(setData);
}, [count]);
- This
useEffectruns after the component renders and fetches data from an API when thecountstate changes.
What About Neither?
Sometimes, you don’t need either hook. Local variables or event handler logic can suffice for transient or render-specific computations.
function Component() {
const temporaryValue = Math.random(); // No need for useState
return <p>{temporaryValue}</p>;
}
Local variables are used for data that only exists during one render. These are quick calculations or values that don’t need to be persisted across renders.
When to Use What?
Decision Workflow

1. Use useState When
- Data changes over time and impacts the UI.
- The component needs to “remember” values between renders.
- Examples: Form inputs, counters, toggles.
function Toggle() {
const [isOn, setIsOn] = useState(false);
return <button onClick={() => setIsOn(!isOn)}>{isOn ? 'On' : 'Off'}</button>;
}
- useState is used here to track whether the button is on or off. Whenever the state (
isOn) changes, the component re-renders, updating the text on the button.
2. Use useEffect When
- You need to perform side effects (e.g., fetch data, update DOM).
- Code must run at specific lifecycle points (mount, update, unmount).
- Examples: API calls, subscriptions, timers.
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(res => res.json())
.then(setData);
}, []); // Runs once on mount
return <div>{data ? data.message : 'Loading...'}</div>;
}
- useEffect runs once when the component mounts (because of the empty dependency array
[]). It fetches data from an API and updates thedatastate with the response.
3. Use Neither When
- Data is transient and doesn’t need to persist across renders.
- Logic can be handled in render or event handlers.
- Examples: Temporary calculations, one-off event responses.
function Calculator() {
const handleAdd = () => {
const a = 5; // Local variable, no state needed
const b = 10;
alert(a + b);
};
return <button onClick={handleAdd}>Add</button>;
}
- Here, the
handleAddfunction uses local variables (aandb) for one-off calculations. Since there’s no need for the values to persist between renders,useStateoruseEffectis unnecessary.
Key Differences
| Feature | useState | useEffect |
|---|---|---|
| Purpose | Manage state | Handle side effects |
| Triggers Render | Yes, when state updates | No, runs after render |
| Runs When | On state change | On mount/update/unmount |
| Dependency | None | Optional dependency array |
| Use Case | UI-related data | External interactions |

Practical Examples
Example 1: Counter with Title Update
function Counter() {
const [count, setCount] = useState(0); // State for UI
useEffect(() => {
document.title = `Count: ${count}`; // Side effect
}, [count]); // Runs when count changes
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
- useState: Manages
countfor the UI. Every time the state changes, the component re-renders, showing the newcount. - useEffect: Updates the document title as a side effect, which runs every time
countchanges. The empty dependency array ensures this only runs whencountupdates.
Example 2: Form with Validation
function Form() {
const [input, setInput] = useState(''); // State for input
const isValid = input.length > 3; // Local variable, no hook needed
return (
<div>
<input value={input} onChange={e => setInput(e.target.value)} />
<p>{isValid ? 'Valid' : 'Too short'}</p>
</div>
);
}
- useState: Tracks
inputfor the form. The state is updated as the user types. - Neither:
isValidis computed directly from theinputvalue in the render function. SinceisValidis only used for display, no state or effect is needed.
Example 3: Fetching Data with Cleanup
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => setSeconds(s => s + 1), 1000);
return () => clearInterval(interval); // Cleanup
}, []); // Runs once on mount
return <p>Seconds: {seconds}</p>;
}
- useState: Tracks
secondsfor the UI. This state is updated every second. - useEffect: Sets up an interval to update
secondsevery second. The cleanup functionclearIntervalensures that the interval is cleared when the component unmounts.
How to Decide: A Checklist
- Does the data affect the UI and change over time?
- Yes → Use
useState.
- Yes → Use
- Does it involve external systems or lifecycle events?
- Yes → Use
useEffect.
- Yes → Use
- Is it a one-off calculation or event-driven logic?
- Yes → Use local variables or event handlers.

Additional Resources
Official Documentation
Video Tutorials
- 🎥 Learn useState in 15 Minutes
- 🎥 Learn useEffect In 13 Minutes
- 🎥 Hooks Explained: useState vs useEffect
Blogs and Articles
Tools
- 🔌 ESLint Plugin for React Hooks - Catches dependency array issues.