Understanding useState Hook with a real-world example - Part 1

Understanding useState Hook with a real-world example - Part 1

·

5 min read

If you are starting with react useState Hook is the first thing that you should understand and practice. I started learning React a few months back. When I started, I made a few apps with just useState hook. And then when I learned useContext,useReducer hook I was able to understand and appreciate it more. So if you practice useState well before moving on to other hooks you will realize the pain points and know why exactly are we using those hooks.

Now let's see what is useState, how and when to use it.

useState is a function that takes an initial value and returns an array with a state variable and a function through which you can update that state variable.

  • useState hook should be used in a functional component or custom hook. It cannot be used in loops, conditions, or nested functions.

Before going to the real-time example let's take a very basic and standard example to understand how useState works.

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

Here initial value is for the count. We take count as a number so we set the initial value to 0. Now whenever we want to update the value of the state variable i.e count, we can do it only via setCount function.

In this counter example, we have put the count variable in the state because its value is changing and the change is reflected on the screen. If the value is constant we don't need a state for it.

We can have an array, string, boolean, object also as a state variable. We can initialize it accordingly. We will see that in part 2.

import { useState } from "react";

export default function App() {
  console.log("line 4");

  const [count, setCount] = useState(0);
  console.log("line 7 - count:", count);

  function increaseCount() {
    console.log("on click");
    setCount(count + 1);
    console.log("line 12 - count", count);
  }

  console.log("line 15 - count:", count);
  return (
    <div className="App">
      <h1>Counter</h1>
      <button onClick={increaseCount}>ADD</button>
      {count}
    </div>
  );
}

Console output:

Before clicking the button Counter-beforeClick.png

After clicking the button Counter-afterClick.png

We have a button ADD which would increase the count value. The function increaseCount is passed as callback functions which means they are not called until the user clicks on the button.

The flow of the code

It's very important to understand how the flow happens. The initial flow happens from top to bottom. So when the component is loaded, the count variable is initialized to 0, the button is displayed and the count variable is shown. This is the initial render. The state variable initialization happens only once i.e during the initial render.

When the user clicks on the add button,increaseCount function is called. Inside this function, we are updating the value of the count variable through setCount function.

Whenever the setCount function is called, the app component is re-rendered. When the app is re-rendered, React updates the DOM with only what has changed with an algorithm called diffing. Check the console whenever you click the button. But now you might wonder what about the line after the setCount in increaseCounter function. If you check the console.log in line 12, the count is still the same. It's not the updated count. The updated value will be shown only in the next render

Real-world example:

To have a better understanding let's take a real-world example. Toggling between show and hide password

showPassword.png

hidePassword2.png

Let's take it step by step. There are two things that we need to do here. Toggle the text in the button to show/hide, show/hide the text in the input field on clicking the button.

Input text is VISIBLE - Button text "hide"
Input text is HIDDEN - Button text "show"

Now, what do you put in the state? Let's think. What are the things that are changing here? Button text, input text visibility. Instead of having two separate states for it can we have a single state from which we can derive both? Yes. A simple boolean state isPasswordVisible. Initially, the password is hidden. So the initial state is false. This is the only state that we would need.

const [isPasswordVisible, setPasswordVisibility] = useState(false);

Let's see how we can derive the button text from the state variable.

<button>{isPasswordVisible ?"hide":"show"}</button>

To hide and show the text in the input field. We can use the type property of the input tag. If the type is "password", the text is hidden. If the type is "text", the text is visible. Again do we need a state for this? Now, you know the answer. We don't need it. We can derive this from the state variable.

<input type={isPasswordVisible ? "text" : "password"}></input>

So, Anything which can be derived from another state should not be put in the state.

Now, comes the main part. We need to toggle on clicking the button. That can be done by setPasswordVisibility function. But what do we pass inside it? If we make it true now. Next time we won't be able to toggle back.

  • If we want to update the state based on the previous state, we have to pass a callback function to the set function and toggle on the previous state(shown in the snippet).

  • If we want to pass a new value we pass the value directly.

<button
    onClick={() => {
       setPasswordVisibility((previousState) => !previousState); 
    }}>
    {isPasswordVisible ? "hide" : "show"}
</button>

Let's put everything together.

import { useState } from "react";

function TogglePassword() {
  const [isPasswordVisible, setPasswordVisibility] = useState(false);

  return (
    <div>
      <input type={isPasswordVisible ? "text" : "password"}></input>
      <button
        onClick={() => {
          setPasswordVisibility((previousState) => !previousState);
        }}>
        {isPasswordVisible ? "hide" : "show"}
      </button>
    </div>
  );
}
export default function App() {
  return (
    <div className="App">
      <TogglePassword />
    </div>
  );
}

In the above code, I have extracted the TogglePassword as a separate component. So that it can be reused. The component name should always start in capital letters.

I have just covered number and boolean state variable in this post. Will write for arrays and objects in the next part. Thank you for reading. I would love to connect with you on Twitter Linkedin. Happy learning!