how to use `setstate` callback on react hooks

  • Last Update :
  • Techknowledgy :

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. 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. he want to split to another variable that can make you do the next step without wait the setState callback – famfamfam Jun 1 at 10:12

This is our Splunktool team suggestion ✌, we tried and its working fine
//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]);​

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]);

If you want the useEffect callback to be ignored during the first initial render, then modify the code accordingly:

import React, {
   useEffect,
   useRef
} from 'react';

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

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

useEffect(() => {
   // Return early, if this is the first render:
   if (!didMount.current) {
      return didMount.current = true;
   }
   // Paste code to be executed on subsequent renders:
   console.log('Do something after counter has changed', counter);
}, [counter]);

Suggestion : 2

They do not update the state immediately but have queues that are used to update the state object. This is done to improve the performance of the rendering of React components. Even though they are asynchronous, the useState and setState functions do not return promises. Therefore we cannot attach a then handler to it or use async/await to get the updated state values. And if we have some state variables that need to be updated according to another state variable, we cannot rely on the updated state variable synchronously. useState and setState both are asynchronous.

Originally published at https://www.wisdomgeek.com on December 15, 2020.

If you have been writing class components for a while, you might be familiar with the callback functionality that the setState function provides. setState allows a second parameter to be passed to it as a callback. The callback function is invoked whenever the state of the function gets updated.

this.setState(newState, callbackFunction)

But, this callback mechanism does not exist with functional components.

const [state, setState] = useState();
setState(newState, callbackFunction)

The state update usually happens on the next render, but even that can vary. Batching updates is up to react, and there is nothing we can do to change that.

Considering the following example:

export default function useProgressPercentage() {
   const [percentage, setPercentage] = useState(0);
   const [completedRequests, setCompletedRequests] = useState(0);
   const [totalRequests, setTotalRequests] = useState(1);

   const incrementCompletedRequestCount = () => {
      setCompletedRequests((completedRequests) => completedRequests + 1);
      setPercentage(
         Number(((completedRequests / totalRequests) * 100).toFixed(2))
      );
   };
   const incrementDataLoadRequestCount = () => {
      setTotalRequests((totalRequests) => totalRequests + 1);
      setPercentage(
         Number(((completedRequests / totalRequests) * 100).toFixed(2))
      );
   };

   return [
      percentage,
      incrementCompletedRequestCount,
      incrementDataLoadRequestCount,
   ];
}

In React functional components, a callback function for anything can be implemented using the useEffect hook. We will be using the same to provide callback functionality to our useState hook to make it function similar to setState.

We will be making use of the dependency array of the useEffect to achieve this. If you are not familiar with it, we recommend reading our post on useEffect react hook.

const [state, setState] = useState();
useEffect(() => {
   callbackFunction()
}, [state])

Note: If you want the changes performed in the callback function to be reflected in the component’s rendered output, you would want to use useLayoutEffect instead of the useEffect react hook.

Therefore, our percentage hook can be updated as follows:

export default function useProgressPercentage() {
   const [percentage, setPercentage] = useState(0);
   const [completedRequests, setCompletedRequests] = useState(0);
   const [totalRequests, setTotalRequests] = useState(1);

   useEffect(() => {
      setPercentage(
         Number(((completedRequests / totalRequests) * 100).toFixed(2))
      );
   }, [completedRequests, totalRequests]);

   const incrementCompletedRequestCount = () => {
      setCompletedRequests((completedRequests) => completedRequests + 1);
   };
   const incrementDataLoadRequestCount = () => {
      setTotalRequests((totalRequests) => totalRequests + 1);
   };

   return [
      percentage,
      incrementCompletedRequestCount,
      incrementDataLoadRequestCount,
   ];
}

Suggestion : 3

setState Callback in a Class Component import React, { Component } from ‘react’; class App extends Component { constructor(props) { super(props); this. state = { age: 0, }; } // this. checkAge is passed as the callback to setState updateAge = (value) => { this. setState({ age: value}, this. 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.21-May-2019 This function is used to update the state of a component, but it’s important to remember that setState is asynchronous. This can lead to tricky debugging issues in your code.28-Feb-2022

Hello everyone, in this post we will examine how to solve the How To Use `Setstate` Callback On React Hooks programming puzzle.

//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]);

Suggestion : 4

If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value, and return an updated value. Here’s an example of a counter component that uses both forms of setState: If your update function returns the exact same value as the current state, the subsequent rerender will be skipped completely. During subsequent re-renders, the first value returned by useState will always be the most recent state after applying updates.

1._
const [state, setState] = useState(initialState);
2._
setState(newState);
3._
function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}
5._
const [state, setState] = useState(() => {
   const initialState = someExpensiveComputation(props);
   return initialState;
});
6._
useEffect(didUpdate);

Suggestion : 5

Let’s see how to perform a callback inside a React class component after setState executes: To perform an action in a React component after calling setState, such as making an AJAX request or throwing an error, we use the setState callback. Here’s something extremely important to know about state in React: updating a React component’s state is asynchronous. It does not happen immediately.

1._
import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      age: 0,
    };
  }
  
  // this.checkAge is passed as the callback to setState
  updateAge = (value) => {
    this.setState({ age: value}, this.checkAge);
  };

  checkAge = () => {
    const { age } = this.state;
    if (age !== 0 && age >= 21) {
      // Make API call to /beer
    } else {
      // Throw error 404, beer not found
    }
  };

  render() {
    const { age } = this.state;
    return (
      <div>
        <p>Drinking Age Checker</p>
        <input
          type="number"
          value={age}
          onChange={e => this.updateAge(e.target.value)}
        />
      </div>
    );
  }

}

export default App;
2._
import React, { useEffect, useState } from 'react';

function App() {
  const [age, setAge] = useState(0);
  
  updateAge(value) {
    setAge(value);
  };

  useEffect(() => {
    if (age !== 0 && age >= 21) {
      // Make API call to /beer
    } else {
      // Throw error 404, beer not found
    }
  }, [age]);

  return (
    <div>
      <p>Drinking Age Checker</p>
      <input
        type="number"
        value={age} 
        onChange={e => setAge(e.target.value)}
      />
    </div>
  );
}

export default App;
3._
useEffect(() => {
   if (age !== 0 && age >= 21) {
      // Make API call to /beer
   } else {
      // Throw error 404, beer not found
   }
}, [age]);

Suggestion : 6

If you are looking for an out of the box solution, check out this custom hook that works like useState but accepts as second parameter as callback function: In React Function Components with Hooks, you can implement a callback function for anything using the useEffect hook. For instance, if you want to have a callback function for a state change, you can make the useEffect hook dependent on this state: Note: If you are just looking for an out of the box solution, check out this custom useState hook with callback function. That's what you are going to implement in this tutorial anyway. I will show how this works below as well.

1._
import React from 'react';
const App = () => {  const [count, setCount] = React.useState(0);
  React.useEffect(() => {    if (count > 1) {      console.log('Threshold of over 1 reached.');    } else {      console.log('No threshold reached.');    }  }, [count]);
  const handleClick = () => {    setCount(count + 1);  };
  return (    <div>      <p>{count}</p>
      <button type="button" onClick={handleClick}>        Increase      </button>    </div>  );};
export default App;

The function you pass to the useEffect hook is your callback function which runs after the provided state changes from the useState hook's second argument. If you perform changes in this callback function that should be reflected in your component's rendered output, you may want to use .

import React from 'react';
import useStateWithCallback from 'use-state-with-callback';
const App = () => {  const [count, setCount] = useStateWithCallback(0, count => {    if (count > 1) {      console.log('Threshold of over 1 reached.');    } else {      console.log('No threshold reached.');    }  });
  const handleClick = () => {    setCount(count + 1);  };
  return (    <div>      <p>{count}</p>
      <button type="button" onClick={handleClick}>        Increase      </button>    </div>  );};
export default App;

If you want to have a lazy executable function instead, you can use the library as well:

import React from 'react';import { useStateWithCallbackLazy } from 'use-state-with-callback';
const App = () => {  const [count, setCount] = useStateWithCallbackLazy(0);
  const handleClick = () => {    setCount(count + 1, (currentCount) => {      if (currentCount > 1) {        console.log('Threshold of over 1 reached.');      } else {        console.log('No threshold reached.');      }    });  };
  return (    <div>      <p>{count}</p>
      <button type="button" onClick={handleClick}>        Increase      </button>    </div>  );};
export default App;

Suggestion : 7

When the state is actually set can vary. Usually it happens on the next render, but it can sometimes be batched for performance. The setState function takes an optional callback parameter that can be used to make updates after the state is changed. Focus on the checkSpeed function. That’s where the setState function gets called. Look at the second argument inside that setState function: it’s calling checkSpeed. 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.

Create a new project by the following command:

 npx create - react - app challan - generator

Now, go to the project directory and start it-

cd challan - generator

npm start

Again start with creating a new file ChallanGenerator.js and this time it’ll be a functional component.

mport React, { useEffect, useState } from 'react';

function ChallanGenerator() {
  const [speed, setSpeed] = useState(0);

  const updateSpeed=(value)=> {
    setSpeed(value);
  };

  useEffect(() => {
    if (speed !== 0 && speed>70) {
 // Make API call to /generate Challan
    } else {
 // Throw error 404, challan not found
    }
  }, [speed]);  	//once the speed is updated useEffect executes

  return (
    <div>
      <p>Challan Generator</p>
      <input
        type="number"
        value={speed} 
        placeholder='miles per hour'
        onChange={e => updateSpeed(e.target.value)}
      />
    </div>
  );
}
export default ChallanGenerator;