We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to publish this job!

Login or register
to save this job!

Login or register
to save interesting jobs!

Login or register
to get access to all your job applications!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel 🚀.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Login or register
to save articles!

Login to see the application

Engineers who find a new job through JavaScript Works average a 15% increase in salary 🚀

You will be redirected back to this page right after signin

Blog hero image

React - Normal State Update vs Functional State Update

Chris 26 November, 2021 | 3 min read

React library

React is essentially a component-based library. You can think of a component as a function which takes in some properties as input and outputs UI element(s). Now a component will need to manage it's own state. So, let's talk about the useState() hook.

useState() Hook

Basically, Hooks are a feature of React that allow us to hook functionality when using functional components. Here is how a basic functional component would look like;

import React, {useState} from "react"; 
const MyTestComponent = () => {
    const [somevalue, setSomeValue] = useState(100);
    return (
        <div>
            <p>{value}</p>
            <button onClick={() => setSomeValue((somevalue + 1))}>Increment Some Value By 1</button>
        </div>
    );
};

The useState() hook allows us to set individual states. When we call useState(), we are kind of declaring a state variable and that state is actually retained between the different function calls. Thus, useState() gives a guarantee that the same value will be retained across renders. React has the ability to retain state values internally ensuring that the updated value is returned each time the function component runs.

The useState() hook accepts an input parameter which is used to set the initial state variable.

import React, {useState} from "react";
const MyTestComponent = () => {
    const [somevalue, setSomeValue] = useState(100);
};

In the example above, the state value would get initialised to 100.

If we pass a function to React’s useState(), it would call that function and use the return value to initialize the state.

import React, {useState} from "react";
const MyTestComponent = () => {
    console.log(“Example of passing function to useState…”)
    const functionForInitialState = () => 100;
    const [somevalue, setSomeValue] = useState(functionForInitialState);
};

This way enables us to use lazy initialisation.

When we use a function, it ensures that the state value is computed only once. This also helps in terms of performance improvement, specifically if the computation is expensive.

Functional variant of useState()

Let us now look at the other variant from useState() hook that supports a functional variant. We will look at some examples which uses the standard update for state(s) as well as the functional update.

export default function App() {
  const [counter, setCounter] = useState(100);
  const firstCallback = () => setCounter((count) => count + 10);
  const secondCallback = useCallback(() => {
    // counter state is re-enclosed within our callback scope ensuring that the state is updated
    setCounter(counter + 10);
  }, [counter]);
  const thirdCallback = useCallback(() => {
    // “counter” value is stale from the initial render
    setCounter(counter + 10);
  }, []); // <-- Here linter also warns about the missing dependency array 

  const fourthCallback = useCallback(() => {
    // This is an example of functional state update avoiding stale state enclosures
    setCounter((count) => count + 10);
  }, []);
  return (
    <div className="App">
      <h1>Counter: {counter}</h1>
      <div>
        <button type="button" onClick={ firstCallback}>
          Increment counter
        </button>
        Example of functional state update
      </div>
      <div>
        <button type="button" onClick={ secondCallback}>
          Increment counter
        </button>
        Example of useCallback with dependency of state to re-enclose state back
      </div>
      <div>
        <button type="button" onClick={ thirdCallback}>
          Increment counter
        </button>
        Example of useCallback without any dependency. This is a standard state update and thus it is a stale state, which would always start from 100
      </div>
      <div>
        <button type="button" onClick={ fourthCallback}>
          Increment counter
        </button>
           Example of useCallback without dependency. This is a functional update and thus it ensures that the state is not stale.
      </div>
    </div>
  );
}

We observed that if the “useCallback” hook is used with no dependencies and if it references any local state, the value seen inside the callback is actually state i.e. from the render cycle that the callback got created. If we try to filter this array, it would always refer to the same initial state, which is stale. Thus, by specifying state i.e. counter here in the array of dependencies, we can kind of enclose the updated “counter” value inside useCallback().

Thus, we can see that for any state updates that rely on the previous state value, we should use the functional variant of state update. The counter example in this case is one of the use cases in React and we need to know the previous count value and then add 10 in this case to return the new state. There can be other use cases like updating complex arrays/objects and where we would need to shallow copy the previous state value into new reference for the piece of state that we are going to update. If we simply want to replace the object/array and don't actually need the previous state, the regular state update should work fine as well.

Here is another example to show the difference between regular and functional variant of state updates.

import React, { useState } from "react";
import "./styles.css";
const App = () => {
  const [counter, setCounter] = useState(100);
  /**
   * counter + 10 handler using the normal state update
   */
  const handler1 = () => {
    // assume counter equals some number num
    setCounter(counter + 10); // update queued, counter === num, counter = num + 10    setCounter(counter + 10); // update queued, counter === num, counter = num + 10    setCounter(counter + 10); // update queued, counter === num, counter = num + 10    // when processed the counter will be num + 10
  };

  /**
   * counter + 10 handler using functional state update
   */
  const handler2 = () => {
    // assume “counter” equals some number num
    setCounter((counter) => counter + 10); // update is queued, counter === num + 0, counter = previouscounter + 10
    setCounter((counter) => counter + 10); // update is queued, counter === num + 1, counter = previouscounter + 10
    setCounter((counter) => counter + 10); // update is queued, counter === num + 2, counter = previouscounter + 10
    // Here for each setState call, it uses the prior result and then updates the state to the new value    // counter will be num + 10 + 10 + 10 OR num + 30
  };
  return (
    <div className="App">
      <h1>useState Example with Counter</h1>
      <h2>Regular State Update V/s Functional State Update</h2>
      counter: {counter}
      <div>
        <button type="button" onClick={handler1}>
          +10 via the normal state update
        </button>
        <button type="button" onClick={handler2}>
          +10 via the functional state update
        </button>
      </div>
    </div>
  );
};
export default App;

Author's avatar
Chris
I love doing frontend development and am a fan of cutting edge frameworks like React, Angular, Backbone, etc

Related Issues

open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 2
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 2
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 1
  • Intermediate
  • HTML

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through JavaScript Works average a 15% increase in salary.

Start with GitHubStart with Stack OverflowStart with Email