When a react component state changes, the render method is called. Hence for any state change, an action can be performed in the render methods body. Is there a particular use case for the setState callback then?
-
4It is currently unclear what you are asking. Can you include some code? – Davin Tryon Feb 04 '17 at 09:30
-
4The setState callback is for anything you want to do after the state has DEFINITELYbeen changed. Since setState is async, if you want to call a fx and be SURE that the new state is loaded then that's what the callback is for – Jayce444 Feb 04 '17 at 09:46
-
4The use case for setState callback is quite clear. You use it when you want a function to run after a SPECIFIC state has been updated. If you put this function in `render()` instead, it will run every time ANY state is updated, which is probably not what you want. This will also make your code less readable and logical. – M3RS Apr 03 '18 at 14:18
-
One use is when you are using the state for storing a result from the server... you want that right now, not after a render because the state is a custom like... myVar, setMyVar – Jonathan Orrego Nov 14 '22 at 22:32
7 Answers
Yes there is, since setState
works in an asynchronous
way. That means after calling setState
the this.state
variable is not immediately changed. so if you want to perform an action immediately after setting state on a state variable and then return a result, a callback will be useful
Consider the example below
....
changeTitle: function changeTitle (event) {
this.setState({ title: event.target.value });
this.validateTitle();
},
validateTitle: function validateTitle () {
if (this.state.title.length === 0) {
this.setState({ titleError: "Title can't be blank" });
}
},
....
The above code may not work as expected since the title
variable may not have mutated before validation is performed on it. Now you may wonder that we can perform the validation in the render()
function itself but it would be better and a cleaner way if we can handle this in the changeTitle function itself since that would make your code more organised and understandable
In this case callback is useful
....
changeTitle: function changeTitle (event) {
this.setState({ title: event.target.value }, function() {
this.validateTitle();
});
},
validateTitle: function validateTitle () {
if (this.state.title.length === 0) {
this.setState({ titleError: "Title can't be blank" });
}
},
....
Another example will be when you want to dispatch
and action when the state changed. you will want to do it in a callback and not the render()
as it will be called everytime rerendering occurs and hence many such scenarios are possible where you will need callback.
Another case is a API Call
A case may arise when you need to make an API call based on a particular state change, if you do that in the render method, it will be called on every render onState
change or because some Prop passed down to the Child Component
changed.
In this case you would want to use a setState callback
to pass the updated state value to the API call
....
changeTitle: function (event) {
this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
// Call API with the updated value
}
....

- 5,449
- 5
- 32
- 38

- 270,417
- 55
- 406
- 400
-
5I understand that it is asynchronous in nature. My question was is there something specific that only the setState callback can be used for that perhaps the render methods body may not support( Something apart from let's say better code readability.) – Sahil Jain Feb 04 '17 at 10:02
-
@SahilJain Validation is the correct example, you wont want to handle it in the render() function because then it will be called everytime you make any change in the render() you would want to call it only when only the input changes and hence in the function itself – Shubham Khatri Feb 04 '17 at 10:06
-
React forbids to change the state during the render.. So its right to put the validation into the callback. – webdeb Feb 04 '17 at 11:01
-
`if (this.title.length === 0) {` should be `this.state.title.length`, right? – Dmitry Minkovsky Oct 10 '17 at 22:05
-
7First use case is probably not a good idea. setState callbacks trigger after re-render, so you're causing a double render for no good reason. This is exactly the purpose of the function argument (updater). You can just run `setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)` and the change will stack. No double renders necessary. – R Esmond Dec 15 '18 at 18:52
-
this.setState({
name:'value'
},() => {
console.log(this.state.name);
});

- 19,893
- 50
- 121
- 195

- 1,752
- 12
- 16
-
28Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation would greatly improve its long-term value](//meta.stackexchange.com/q/114762/206345) by showing _why_ this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you've made. – Machavity May 30 '18 at 12:42
-
1When you want call a function after the state changed you can use the method. – Araz Babayev May 30 '18 at 12:53
-
what if you wants set multiple porperties of state like name, firstname etc? – Sumanth Varada Aug 13 '19 at 08:46
-
4
The 1. usecase which comes into my mind, is an api
call, which should't go into the render, because it will run for each
state change. And the API call should be only performed on special state change, and not on every render.
changeSearchParams = (params) => {
this.setState({ params }, this.performSearch)
}
performSearch = () => {
API.search(this.state.params, (result) => {
this.setState({ result })
});
}
Hence for any state change, an action can be performed in the render methods body.
Very bad practice, because the render
-method should be pure, it means no actions, state changes, api calls, should be performed, just composite your view and return it. Actions should be performed on some events only. Render is not an event, but componentDidMount
for example.

- 12,993
- 5
- 28
- 44
Consider setState call
this.setState({ counter: this.state.counter + 1 })
IDEA
setState may be called in async function
So you cannot rely on this
. If the above call was made inside a async function this
will refer to state of component at that point of time but we expected this to refer to property inside state at time setState calling or beginning of async task. And as task was async call thus that property may have changed in time being. Thus it is unreliable to use this
keyword to refer to some property of state thus we use callback function whose arguments are previousState and props which means when async task was done and it was time to update state using setState call prevState will refer to state now when setState has not started yet. Ensuring reliability that nextState would not be corrupted.
Wrong Code: would lead to corruption of data
this.setState(
{counter:this.state.counter+1}
);
Correct Code with setState having call back function:
this.setState(
(prevState,props)=>{
return {counter:prevState.counter+1};
}
);
Thus whenever we need to update our current state to next state based on value possed by property just now and all this is happening in async fashion it is good idea to use setState as callback function.
I have tried to explain it in codepen here CODE PEN

- 1,751
- 11
- 13
Sometimes we need a code block where we need to perform some operation right after setState where we are sure the state is being updated. That is where setState callback comes into play
For example, there was a scenario where I needed to enable a modal for 2 customers out of 20 customers, for the customers where we enabled it, there was a set of time taking API calls, so it looked like this
async componentDidMount() {
const appConfig = getCustomerConfig();
this.setState({enableModal: appConfig?.enableFeatures?.paymentModal }, async
()=>{
if(this.state.enableModal){
//make some API call for data needed in poput
}
});
}
enableModal boolean was required in UI blocks in the render function as well, that's why I did setState here, otherwise, could've just checked condition once and either called API set or not.

- 337
- 4
- 12
There is a rare but important case for setState
callback.
You want to recalculate the state after updating property x
and your recalculation may update x
once again. You can't just use useEffect
depending on x
, because React will treat it as 'circular dependency detected'. You can circumvent React by using setState
callback. But please be sure that you are not creating infinite loop.
I've applied this solution for 2 huge React projects.

- 3,294
- 6
- 38
- 62
Functional Components' setState callback
All answers are about how to pass a callback
function to the Class Components' setState function. But for a Functional component I highly recommend to use a custom hook function:
import { useRef, useCallback, useEffect, useState } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import isFunction from 'lodash.isfunction';
type StateFunctionType<S> = Dispatch<SetStateAction<S>>;
export type SetStateCallbackGeneric<S> = (
x: S | StateFunctionType<S>,
cb?: (newState: S) => void
) => void;
const useStateCallback = <T>(
initialState: T
): [T, SetStateCallbackGeneric<T>] => {
const [state, setState] = useState<T>(initialState);
const cbRef = useRef<any>(null);
const setStateCallback: SetStateCallbackGeneric<T> = useCallback(
(newState, cb) => {
cbRef.current = cb;
setState(newState as any);
},
[]
);
useEffect(() => {
if (isFunction(cbRef?.current)) {
// @ts-ignore
cbRef?.current?.(state);
cbRef.current = null;
}
}, [state]);
return [state, setStateCallback];
};
export default useStateCallback;
By using this hook function you can easily pass a callback
function to the setter function, please take a look at an example:
const [text, setText] = useStateCallback<string>('')
const handleFoo = (txt: string) => {
setText(txt, () => {
// Do What you want exactly AFTER text gets updated
})
};

- 29,059
- 15
- 130
- 154