The useState Hook

Introduction

In the realm of modern web development, creating dynamic and interactive UI is a challenge. React js has revolutionized this landscape with it's component based architecture. React provides us with a lot of tools to help build a dynamic website. useState is one such Hook. In this Blog, you're going to learn about the useState Hook which will surely help you a lot in the future when building websites using React.

Understanding State in React

State is the internal data that the component can hold and manage. But why do we need state? We need state to store values that can change over time and affect the UI. State allows us to represent dynamic changes and update UI. This is why state is used and not normal javascript variables when it comes to dynamic user interfaces. If you store UI elements in a normal javascript element, you won't see changes in the UI even if you change value in the variable. State does not have this weakness. But we can't change or update the value of a State directly. That's why we use a utility provided by react called the useState Hook.

Introducing the useState Hook

Hooks are special functions that are only available when React is rendering. They let us "hook into" different features of React. useState is one such Hook in React. Functions starting with "use" are Hooks.

The useState hooks returns an array with two values, a state and a function to update it. Remember, you should never update the state directly. Always use the function when you need to update the state.

💡
Note: You should call useState hook only inside a functional component. Calling it outside a functional component will lead to repeated re-renders, forming an infinite loop and your code won't work.

How to use the useState Hook

You need to import the useState Hook before using it

import {useState} from "react"

Always call the useState hook inside a functional component. This is how you call a useState hook:

const [number, setNumber] = useState(0);

"number" is the state and "setNumber" is the function we use to update the value of the state. Here, we have given "number" an initial value of 0. We could have given it any value or even left it blank. It all depends on what purpose the state serves.

💡
Note: Not all variables needs to be declared as a state. We should use state only if the variable affects UI and is not constant. Normal javascript variables used in calculations and not affecting UI in any way need not be declared as states.

Updating state with useState

In react, you should never update the state variable directly

function update(){
    number = number + 1;
}

In this code snippet, we have updated the state directly. This will not give us an error but the changes will not be reflected in the UI. The "number" state will keep getting updated but it will become out of sync with the UI and this defeats the purpose of using states.

Let us see how to update state using the setter function then:

function update(){
    setNumber(num => num + 1);
}

In this code snippet, we use the "setNumber" function to update the value of the state "number". When we call setNumber, it updates the value of the state and triggers a re-render. This way, the updated value of the state is refl;ected in the UI. If we update the state directly, it will not trigger a re-render and hence the updated value is not reflected in the UI.

An important thing to remember is that the useState function is asynchronous in nature. It does not immediately update the state when you call it. When you call the state update function, React schedules the state update to be processed during the next render cycle. Take a look at this code snippet:

function update(){
    setNumber(num => num + 1);
    console.log(number);
}

Here, the updated value of the state will not be immediately logged out to the console. Let's assume that the value of the state "number" was 10. When we call the state update function "setNumber" to update the value of "number", the state update will be batched to be processed during the next render. The next line will log out the old value of the state as the update is yet to be processed. The value 10 will be logged out to the console. Then when we reach the end of the update function, React will trigger a re-render and the value of the state "number" will be updated to 11.

Let's build a Counter

Let's build a simple counter to demonstrate how useState works.

This is the code:

import "./styles.css";
import {useState} from "react";

export default function App() {

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

  function update(){
    setCount(cnt => cnt + 1);
  }

  return (
    <div className="App">
      <h1>Counter: {count}</h1>
      <button onClick={update}>Click Me!</button>
    </div>
  );
}

Here, we have set count as a state. Whenever we click the button, the update function is called which then calls the state update function. The "setCount" function increases the value of "count" by 1 and triggers a re-render. The updated value of count is then reflected in the UI.

Multiple useState Hooks

When building complex components, you'll encounter scenarios where different states need to be managed independently. This is where multiple useState hooks come into play. You can manage the different independent states using different useState hooks such that each state will work independently. Let us modify the example of a counter by adding 2 counters.

Code:

import "./styles.css";
import { useState } from "react";

export default function App() {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);

  function update1() {
    setCount1((cnt) => cnt + 1);
  }

  function update2() {
    setCount2((cnt) => cnt + 1);
  }

  return (
    <div className="App">
      <h1>First Counter: {count1}</h1>
      <button onClick={update1}>Update First Counter</button>
      <h1>Second Counter: {count2}</h1>
      <button onClick={update2}>Update Second Counter</button>
    </div>
  );
}

In the above example, we have used two useState functions to manage the 2 counters individually. The code is almost similiar to the previous example. The only difference is that we need to add two useStates and write the update function of the second counter in the same way. You need not worry about the two states being overlapped as React internally manages each state using different useState functions independently. When the components become more and more complex, you will need to handle more states independently and using multiple useState Hooks will be very helpful.

Conclusion

In the ever-evolving landscape of React development, the useState hook has emerged as a versatile and essential tool for managing state within functional components. It offers a powerful yet elegant solution to the challenges of creating dynamic and interactive user interfaces.

So, armed with the knowledge gained here, set forth into the realms of React with confidence. Embrace the power of useState and other hooks as you create applications that engage users, adapt to their actions, and offer memorable experiences.


Connect With Me

If you're interested in topics like Web Development and Javascript, feel free to connect with me.

LinkedIn: https://www.linkedin.com/in/maanav-nair-2a8049253/

Twitter: https://twitter.com/maanav_nair