DEV Community

Mihir Chhatre
Mihir Chhatre

Posted on • Updated on

React useState() đŸĒ

Let us first understand state in React.

State can be imagined as the data or property that is used within an application. These data/property values would likely change over time and the State hook in React helps us track & manage the changing states.

To use the State hook, we need to import it as shown below:

import React, {useState} from 'react'

We can then invoke useState() inside the component function and pass an initial state(this value can be any type such as string, number or object) as an argument:

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

The useState() hook returns an array, where the first element corresponds to the current state and the second element is a function that allows us to update the current state.

Let's get building 🏗ī¸

Consider the code for a simple counter functionality -

import React, {useState} from 'react'

const App = () => {

    const [count, setCountValue] = useState(1)

    const decrement = () => {
        setCountValue(prevState => {
            prevState-1
        })
    }

    const increment = () => {
        setCountValue(prevState => {
            prevState+1
        })
    }

    return(
        <div>
            <button onClick={decrement}> - </button>
            <span> {count} </span>
            <button onClick={increment}> + </button>
        </div>
    )
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Simplifying the code above...

useState() is called within the component function and an initial state(1) is passed to it. This means that when the component is rendered for the first time(when the page is loaded initially), the counter is set to 1.

As mentioned earlier, useState() returns an array with two elements. Here, using array destructing, the current state is stored in the count variable and the function to update the current state is setCountValue.

The + button triggers the increment function and - triggers the decrement function. I am using the setCountValue function to update the current state value.

Let's have a look at a common mistake developers tend to make when trying to update the state using the previous state :

const decrement = () => {
        setCountValue(count - 1)
    }
Enter fullscreen mode Exit fullscreen mode

Why is the above approach an incorrect one to update the state value?
When we modify the state using the previous state value(in the above code we are using the count variable directly), we must use the function version of setting state as shown below.

const decrement = () => {
        setCountValue(prevState => {
            prevState-1
        })
    }
Enter fullscreen mode Exit fullscreen mode

prevState is the previous state snapshot that React provides. The reason behind using this approach is that the state updating function in React schedules the state update. By using the function version to set the state, we can ensure that the previous state is always updated(latest).


Diving deeper into useState()

Each time the state updating function is called, the state is updated and the component function from which the useState() is initialized is executed again.

It is also important to remember that useState() registers a different state for each component instance and React manages states independently on a per-component basis.

Here are two frequently frequently asked questions when using useState():

  1. Why does useState() use const since the state value is updated?
    --> The way to think about this question is that each time the component is rendered(state update function is called), a new variable is created and managed somewhere else, internally, by React.

  2. Does the default state not override the current state value each time the state updating function is called and the component is rendered?
    --> React keeps track of the first instance where useState() was called and prevents any default state overwrites during subsequent component renders.

Another important concept to understand is how to work with objects and useState():

    const [state, setState] = useState({count:4, toggle:'Yes'})
    const count = state.count
    const toggle = state.toggle

    function decrement() {
        setState((prevState) => {
            return ({
                count: prevState.count-1
            })
        })
    }
Enter fullscreen mode Exit fullscreen mode

The above code is incorrect since the setState update function overrides the previous state with only the updated count(toggle:'Yes' is removed).

The correct way to use an object is to spread the previous state and then set the new state -

    function decrement() {
        setState((prevState) => {
            return ({
                ...prevState,
                count: prevState.count-1
            })
        })
    }
Enter fullscreen mode Exit fullscreen mode

Finally, lets talk about an advance concept when using useState().

Consider setting the initial state as a: useState('a'). When using state hook, the initial state a is called each time the function is run. If a computationally complex argument is defined as the initial state, it would run during every subsequent component function render, leading to a degradation in performance.

Therefore, there is another way to pass state to useState(), a function version.
useState(() => {return 4})

The approach runs the initial state function only during the first component render. This approach is preferred when we have a computationally intensive initial state.


The gamut of information around useState() can be overwhelming đŸ¤¯. Remember to go slow and understand the concepts as it would you build a đŸ’Ē base in React.

Top comments (0)