Last updated
Aug 18, 2025
7 mins read
Share on

Generate React UI with Prompts or Figma
Topics

Software Development Executive - I
Writes code, blogs, and product docs. She loves a good meal, a great playlist, and a clean commit history. When she’s not debugging, she’s probably experimenting with a new recipe.

DevRel Engineer
Product-led Growth, Technical Content on product's feature awareness through use cases, Community on Discord, Frontend architect for latency and performance with 6+ years of experience, Tinkerer, Thinker.
Is setState synchronous or asynchronous?
Can I use setState callback in functional components?
What happens if I call setState multiple times?
Should I always use a callback function with setState?
Confused by React’s setState callback? Learn how async updates flow and when a callback makes state changes reliable. Catch common pitfalls, grab clear patterns, and use a simple mental model to keep components predictable.
React developers often face challenges when working with asynchronous updates in component state. While the setState Function may look fairly simple, but its behavior can surprise beginners and even confuse those with experience. The React setState callback feature provides a way to gain more control over these updates.
But how can you use it properly without creating bugs or hurting performance?
Let’s break this down step by step and turn a tricky topic into something that feels natural.
React does not apply the setState function updates immediately. Instead, updates are batched for better perceived performance. This batching helps the user interface remain smooth and responsive, even when multiple updates are triggered quickly. But this also means that calling setstate does not guarantee an immediate command to update the state variable.
If you log the current state right after updating, you often won’t see the updated value. Instead, you might see the previous state. This can confuse new developers who expect an immediately updated value. The truth is, React schedules the update internally, and the render method reflects the change only after the reconciliation process.
This raises a question: How can you be sure the update is finished before running another function that depends on it?
That’s where the setstate callback comes in.
When you call the setstate function in a class component, you can pass a callback function as the second argument. This second argument runs only after React finishes updating the state and re-rendering the react component.
import React, { Component } from "react"; class Counter extends Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState( { count: this.state.count + 1 }, () => { console.log("Updated count:", this.state.count); // runs after update } ); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.handleClick}>Increase</button> </div> ); } } export default Counter;
Explanation:
this.setState takes two parameters: the state object (or updater function) and a callback function.callback function here logs the updated state after React completes the update cycle.previous state.This guarantees that your logic runs only after the update is reflected in the component’s state.
“Provide callback to useState hook like setState” — a post highlighting the importance of callbacks in state logic.- View complete post on LinkedIn
The setstate function accepts:
| Parameter | Description |
|---|---|
| First argument | New or an based on the previous state. |
| Second argument | A that runs after the update and re render. |
This structure makes the setstate method the primary method of managing state updates in class components.
Here’s a simple flow to help:
Explanation:
The diagram shows how leads to re rendering. Only after the completes, the (callback) runs. This tells react to execute code that depends on the updated state safely.
In a , using the is common. But in a , the behavior is different. Here we use .
Example:
Explanation:
This difference is key. Functional components encourage declarative logic where you specify dependencies instead of attaching a second argument callback.
You don’t always need a . But there are cases where it’s very handy:
The callback ensures predictable timing for these scenarios.
Explanation:
Here the ensures we log the data only after the component’s state has updated and the has run. Without this, you might see stale data. This is common in handling.
Solution: Use the callback.
This may not give the you expect. Instead, use the :
Sometimes too many updates hurt performance. Combine related updates into one call to avoid unnecessary re renders.
Want to skip writing complex state management code? Rocket.new lets you build any app with simple prompts – no code required. Save time, avoid errors, and focus on the big picture instead of struggling with the details.
The is more than just a second parameter. It gives you precise control over when a function runs after a state update. Whether you are building with or shifting to , understanding callbacks helps you avoid bugs, handle async data, and write predictable code. By mastering this pattern, you’ll improve the reliability of your updates.
state objectupdater functionsetstate callback functioncalling setstaterender methodsecond argumentreact class componentsetstate callbackfunctional componentusestate and useeffect hooksuseeffect functionsetstate callback functionstate variablecountuseeffect function executesuseeffect hooksetstate callbackapi callajax requestchild componentevent handlersinfinite loopnext rendersetstate callbackrender methodserver responsessecond argumentnew stateupdater argumentsetstate methodsetstate callback functionfunctional componentsuseeffect hookmutable objectsnew stateupdater functionevent handlersfunctional componentsuseeffect hookmutable objectsnew stateupdater functionevent handlerssetstate callbackclass componentfunctional componentsreact componentimport React, { useState, useEffect } from "react";
function CounterFC() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Updated count:", count);
}, [count]); // useeffect function executes after state changes
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
export default CounterFC;
class UserData extends React.Component {
state = { user: null };
fetchData = () => {
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(res => res.json())
.then(data => {
this.setState({ user: data }, () => {
console.log("User loaded:", this.state.user);
});
});
};
render() {
return (
<div>
<button onClick={this.fetchData}>Load User</button>
{this.state.user && <p>{this.state.user.name}</p>}
</div>
);
}
}
export default UserData;
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // still old value
this.setState({ count: this.state.count + 1 });
this.setState({ count: this.state.count + 1 });
this.setState(prev => ({ count: prev.count + 1 }));
this.setState(prev => ({ count: prev.count + 1 }));