How to use `setState` callback on react hooks

setstate callback hooks
react setstate callback
react hooks setstate
react setstate callback not working
use-state-with-callback
passing callbacks down with react hooks
usememo example
react hooks props

React hooks introduces useState for setting component state. But how can I use hooks to replace the callback like below code:

setState(
  { name: "Michael" },
  () => console.log(this.state)
);

I want to do something after the state is updated.

I know I can use useEffect to do the extra things but I have to check the state previous value which requires a bit code. I am looking for a simple solution which can be used with useState hook.

You need to use useEffect hook to achieve this.

const [counter, setCounter] = useState(0);

const doSomething = () => {
  setCounter(123);
}

useEffect(() => {
   console.log('Do something after counter has changed', counter);
}, [counter]);

How to use `setState` callback on react hooks, If you want the setState callback to be executed with the hooks then use flag variable and give IF ELSE OR IF block inside useEffect so that when that conditions are satisfied then only that code block execute. The setState function takes an optional callback parameter that can be used to make updates after the state is changed. So, basically to perform an action such as making an AJAX request or throwing an error, after calling setState in a react component we use setState Callback function. setState Callback in a Class Component

If you want to update previous state then you can do like this in hooks:

const [count, setCount] = useState(0);


setCount(previousCount => previousCount + 1);

React useState with Callback, If you have used setState before, you may be missing a callback If you have started to use React's useState hook for your application, you� setState Callback in a Functional Component React 16.8 introduced Hooks which gave us a way to add state to functional components through the useState Hook. However, the useState Hook does not have a second callback argument. Instead, we use the useEffect Hook and its second argument, which is an array of dependencies.

I Think, using useEffect is not an intuitive way.

I created a wrapper for this. In this custom hook, you can transmit your callback to setState parameter instead of useState parameter.

I just created Typescript version. So if you need to use this in Javascript, just remove some type notation from code.

Usage
const [state, setState] = useStateCallback(1);
setState(2, (n) => {
  console.log(n) // 2
});
Declaration
import { SetStateAction, useCallback, useEffect, useRef, useState } from 'react';

type Callback<T> = (value?: T) => void;
type DispatchWithCallback<T> = (value: T, callback?: Callback<T>) => void;

function useStateCallback<T>(initialState: T | (() => T)): [T, DispatchWithCallback<SetStateAction<T>>] {
  const [state, _setState] = useState(initialState);

  const callbackRef = useRef<Callback<T>>();
  const isFirstCallbackCall = useRef<boolean>(true);

  const setState = useCallback((setStateAction: SetStateAction<T>, callback?: Callback<T>): void => {
    callbackRef.current = callback;
    _setState(setStateAction);
  }, []);

  useEffect(() => {
    if (isFirstCallbackCall.current) {
      isFirstCallbackCall.current = false;
      return;
    }
    callbackRef.current?.(state);
  }, [state]);

  return [state, setState];
}

export default useStateCallback;

Set a callback to setState(useState) in React funtional Component , It is hard sometime to call something after updating the state using useState hook in functional component in React. Here is a simple trick:. setState takes a callback as its second argument. We’ve looked at handling asynchronous state with lifecycle methods. But, to be honest, it’s a lot of ceremony for some simple needs. Fortunately, setState takes a callback. We can use the setState callback to keep state-handling close to set-setting.

useEffect, that only fires on state updates:

const [state, setState] = useState({ name: "Michael" })
const isFirstRender = useRef(true)

useEffect(() => {
  if (!isFirstRender.current) {
    console.log(state) // do something after state has updated
  }
}, [state])

useEffect(() => { 
  isFirstRender.current = false // toggle flag after first render/mounting
}, [])

Above will mimic the setState callback best and not fire for initial state. You can extract a custom Hook from it:

function useEffectUpdate(effect, deps) {
  const isFirstRender = useRef(true) 

  useEffect(() => {
    if (!isFirstRender.current) {
      effect()
    }  
  }, deps) // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    isFirstRender.current = false;
  }, []);
}

// ... Usage inside component
useEffectUpdate(() => { console.log(state) }, [state])

Hooks API Reference – React, They let you use state and other React features without writing a class. useReducer; useCallback; useMemo; useRef; useImperativeHandle; useLayoutEffect Unlike the setState method found in class components, useState does not� They let you use state and other React features without writing a class. The introduction page used this example to get familiar with Hooks: import React , { useState } from 'react' ; function Example ( ) { // Declare a new state variable, which we'll call "count" const [ count , setCount ] = useState ( 0 ) ; return ( < div > < p > You clicked { count } times </ p > < button onClick = { ( ) => setCount ( count + 1 ) } > Click me </ button > </ div > ) ; }

Your question is very valid.Let me tell you that useEffect run once by default and after every time the dependency array changes.

check the example below::

import React,{ useEffect, useState } from "react";

const App = () => {
  const [age, setAge] = useState(0);
  const [ageFlag, setAgeFlag] = useState(false);

  const updateAge = ()=>{
    setAgeFlag(false);
    setAge(age+1);
    setAgeFlag(true);
  };

  useEffect(() => {
    if(!ageFlag){
      console.log('effect called without change - by default');
    }
    else{
      console.log('effect called with change ');
    }
  }, [ageFlag,age]);

  return (
    <form>
      <h2>hooks demo effect.....</h2>
      {age}
      <button onClick={updateAge}>Text</button>
    </form>
  );
}

export default App;

If you want the setState callback to be executed with the hooks then use flag variable and give IF ELSE OR IF block inside useEffect so that when that conditions are satisfied then only that code block execute. Howsoever times effect runs as dependency array changes but that IF code inside effect will execute only on that specific conditions.

[hooks] useState, Is there a plan to introduce it later on? The reason I ask is that during the past years of react usage I found a few scenarios (very rarely though)� React useContextSelector hook in userland. Note: the introduction of hooks in React 16. Unfortunately, it is not working in hook. This function will receive the previous state from react. setState React promise tracker implements a custom hook that can report the current status to our loading indicator component. 13 introduced a major change in how you can define your component classes.

React Hooks, Hello! What is the best way to call a function after a setState using React Hooks? I want to call a toggle callback passing the new value. Call useState() hook to enable state in a functional component. The first argument of the useState(initialValue) is the state’s initial value. [state, setState] = useState(initialValue) returns an array of 2 items: the state value and a state updater function. Invoking the state updater function setState(newState) with the new value updates the state.

How to Use callBack With setState in React -, To update the state of a component, we use the setState method. However it is React hooks provide useState to define states inside functional components. The second parameter to setState()is an optional callback function that will be executed once setStateis completed and the component is re-rendered. Generally we recommend using componentDidUpdate()for such logic instead. And use componentDidUpdateis what we're gonna do. Or at least the hooks equivalent of it.

Why React setState/useState does not update immediately, useState hook has triggered? Use React useEffect after state has changed. React.useState doesn't have accept callback function that gets called after React state� import React, { useCallback } from 'react'. This hook is useful when you have a component with a child frequently re-rendering, and you pass a callback to it: import React, { useState, useCallback } from 'react' const Counter = () => { const [count, setCount] = useState(0) const [otherCounter, setOtherCounter] = useState(0) const increment = () => { setCount(count + 1) } const decrement = () => { setCount(count - 1) } const incrementOtherCounter = () => { setOtherCounter(otherCounter + 1) }

Comments
  • in class component, I used async and await to achieve the same result like what you did to add a callback in setState. Unfortunately, it is not working in hook. Even if I added async and await , react will not wait for state to update. Maybe useEffect is the only way to do it.
  • @Zhao, you did not mark the correct answer yet. Can you kindly spare few seconds
  • This will fire the console.log on the first render as well as any time counter changes. What if you only want to do something after the state has been updated but not on initial render as the initial value is set? I guess you could check the value in useEffect and decide if you want to do something then. Would that be considered best practice?
  • To avoid running useEffect on initial render, you can create a custom useEffect hook, which doesn't run on initial render. To create such a hook, you can check out this question: stackoverflow.com/questions/53253940/…
  • And what about case, when i want to call different callbacks in different setState calls, which will change same state value? You answer is wrong, and in shouldn't be marked as correct to not confusing newbies. The true is that setState callbacks its one of the hardest problems while migrating on hooks from classes which hasn't one clear solving method. Sometimes you really wil be enougth some value-depending effect, and sometimes it'll requires some hacky methods, like saving some kind of flags in Refs.
  • I think by setCounter you mean setCount
  • This won't work. You don't know in which order the three statements inside updateAge will actually work. All three are async. The Only thing guaranteed is that first line runs before 3rd (since they work on same state). You don't know anything about 2nd line. This example is too simle to see this.
  • My friend mohit. I have implemented this technique in a big complex react project when i was moving from react classes to hooks and it works perfectly. Simply try the same logic anywhere in hooks for replacing setState callback and you will know.
  • "works in my project isn't an explanation" , read the docs. They are not synchronous at all. You can't say for sure that the three lines in updateAge would work in that order. If it was in sync then whats need of flag, directly call console.log() line after setAge.
  • useRef is a much better solution for "ageFlag".
  • setCounter is async you don't know if console.log will be called after setCounter or before.