Understanding the React useState() Hook

Understanding the React useState() Hook

ยท

6 min read

Introduction

Hooks were introduced in React v16.8.0. Prior to that, if we had written a functional component and wanted to add state or make use of lifecycle methods to perform operations such as data fetching and manual DOM manipulation, the functional component had to be converted into class based component.

However, introduction of Hooks made adding state and performing those operations in functional component possible. It also helped in keeping the mutually related code together rather than splitting the code based on lifecycle methods. Hooks don't work inside classes rather they let us work with React without the need for class.

In this post, we will learn about the built-in useState() Hook and how to use it in a functional component. We will also understand the difference in initializing, updating and accessing the state in class component as compared to functional component.

Rules of Hooks

Following are the two rules of Hooks that needs to be followed:

  • Hooks should always be called at the top level of the React function which means it shouldn't be called inside loops, conditionals or nested functions. This is done to ensure that Hooks are called in the same order each time a component renders.

  • Never call Hooks from regular JavaScript functions. Instead, call it from React function components or custom Hooks.

useState() Hook

As the name suggests, useState Hook is used to add state to function components.

The syntax for useState is as below:

const [state, setState] = useState(initialState);

// assigns initialState to state
// setState function is used to update the state

useState() returns an array with exact two values. Array destructuring can be used to store these values in different variables.

The first value returned represents the state and the second value returned is a function that can be used to update the state. You can give any name to these two variables. For our understanding, we'll name the state variable as state and the function that updates it as setState. You can follow this convention of assigning any name to state variable and then prefixing it with 'set' to form the function name.

The 'initialState' argument passed to useState sets the initial state. On subsequent re-renders, state is updated through the setState function returned from the useState Hook.

Now, let's take a look at the following code block which represents a class component with state

import React, { Component } from "react";

export default class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      weather: 'hot',
      disabled: false
    }
  }

  render() {
    return (
      <div>
        <p>The weather is {this.state.weather}</p>
        <button 
            onClick={() => this.setState({weather: 'cloudy', disabled: !this.state.disabled})} 
            disabled={this.state.disabled}>
            Change weather
        </button>
      </div>
    );
  }
}

When the above class component gets rendered to the screen, you get a paragraph The weather is hot with a 'Change weather' button below it.

On clicking the button, the component re-renders and output changes to The weather is cloudy with the button getting disabled.

In a class component, you can initialize state in the constructor by using this.state. In the above example, it is initialized to {weather: 'hot', disabled: false}. Any update to state is done through this.setState and respective values can be accessed using this.state.weather and this.state.disabled.

The state is defined as an object and all the state updates done through this.setState is merged into that object as class component can have a single state object only. Therefore, {weather: 'cloudy', disabled: !this.state.disabled} gets merged with the previous value and state is updated.

In order to initialize, update or access any value from state in a class component, you always need to use this keyword.

Now, let's take a look at the following functional component using the State Hook that works the same way as the earlier class component

// import useState Hook from "react" package
import React, { useState } from "react";

export default function App() {

  const [weather, setWeather] = useState('hot');    // "weather" value initialized to "hot"
  const [disabled, setDisabled] = useState(false);  // "disabled" value initialized to "false" 
  return (
    <div>
      <p>The weather is {weather}</p>
      <button onClick={() => {
        setWeather('cloudy');     // setWeather('cloudy') updates the "weather" to "cloudy"
        setDisabled(!disabled);   // setDisabled(!disabled) updates the "disabled" to "true"
      }} disabled={disabled}>Change weather</button>
    </div>
  );
}
  • In order to use state in functional component, you first need to import useState Hook from React.

  • Unlike class component where you can have a single state object only, functional component allows you to have multiple state variables. Here, weather and disabled state variables are initialized to the argument passed to useState Hook.

  • This argument can be of any type such as number, string, array or object unlike class component where state is initialized to object only.

  • On clicking the button, setWeather and setDisabled functions are called with new state values passed to it. React will then re-render the component by passing the new weather and disabled values to it.

  • In a functional component, updating a state value always replaces the previous value unlike class component where state updates are merged.

In the above example, new state values are not dependent on previous state values. Therefore, we directly pass new value to state update function. In scenarios where new state value depends on previous state value, you can use the following functional update format to update the state.

setState(previousStateValue => {
    // newStateValue determined using previousStateValue
    return newStateValue;
})

This functional update format is used to update the state depending on the previous state value.

Conclusion

In this post, you learnt about the useState() Hook that makes it possible to use state in a functional component without transforming it into a class component. You learnt how to initialize, update and access the state variables in a functional component using Hooks.


Thank you for taking the time to read this post ๐Ÿ˜Š Hope this post helped you!! Please share if you liked it.

I would love to connect with you on Twitter. Do share your valuable feedback and suggestions you have for me ๐Ÿ‘‹