How to update state that depends on previous state in React JS

To work with the web frontend It is needed to work with the state while working in React. States are basically used for storing data in React.

These are the perfect alternatives to regular JavaScript variables in various ways. Sometimes it is needed to declare multiple values in a single state. If that isn’t handled properly, it might cause errors in further progress.

In this article, we will look into, how to declare a state that can hold multiple values and we can change those values that depend on previous values and change the value.

Below are the steps that we will be following, Create React project

  • Create a form
  • Create a state to hold form data
  • Change the state according to the input values

Create React project

To create a React project,

  • Run the below commands in the command prompt.
npx create-react-app my-app
cd my-app
npm start
  • Open the app.js file from the src folder in the project directory

// src/App.js

import React, { useEffect, useState } from "react";

function App() {
  
  return (

    <div>
      
    </div>
  );

}

export default App;

Note: You can learn more about creating a react project from here.

Create a form

  • Create a form with some input fields in the app.js file
// src/App.js

import React, { useEffect, useState } from "react";

function App() {

  return (

    <div className=" flex justify-center lg:h-screen items-center">
      <div className="card w-full md:w-96 items-center shadow-2xl bg-base-100">
        <form className="card-body w-full lg:w-96">
          <div className="form-control">
            <label className="label">
              <span className="label-text">Name</span>
            </label>
            <input
              type="text" placeholder="name" className="input input-bordered" />

          </div>

          <div className="form-control">
            <label className="label">
              <span className="label-text">Email</span>
            </label>
            <input
              type="email" placeholder="email" className="input input-bordered" />

          </div>

          <div className="form-control mt-6">
            <button type="submit" className="btn btn-primary">Check Data</button>
          </div>

        </form>



      </div>
    </div>
  );

}

export default App;

Here, we have created a form that contains two input fields for name and email. And we have used Tailwind CSS for styling purposes. Please Read this article to know about it more.

Create a state to hold the input data

  • Create a single state with a default value of empty object properties to store the data from the input form
const [formData, setFormData] = useState({
    name: "",
    email: ""
  })

Here, we have declared a state to hold form data. Please read this to know more about changing state values.

// src/App.js

import React, { useEffect, useState } from "react";

function App() {
  const [formData, setFormData] = useState({
    name: "",
    email: ""
  })
  return (

    <div className=" flex justify-center lg:h-screen items-center">
      <div className="card w-full md:w-96 items-center shadow-2xl bg-base-100">
        <form className="card-body w-full lg:w-96">
          <div className="form-control">
            <label className="label">
              <span className="label-text">Name</span>
            </label>
            <input
              type="text" placeholder="name" className="input input-bordered" />

          </div>

          <div className="form-control">
            <label className="label">
              <span className="label-text">Email</span>
            </label>
            <input
              type="email" placeholder="email" className="input input-bordered" />

          </div>

          <div className="form-control mt-6">
            <button type="submit" className="btn btn-primary">Check Data</button>
          </div>

        </form>



      </div>
    </div>
  );

}

export default App;

Change state according to its input value

  • Declare two functions to store input values into that state
// function for store name
  const handleNameChange = e => {
    setFormData(previousState => {
      return { ...previousState, name: e.target.value }
    })
  }
  // function for store email
  const handleEmailChange = e => {
    setFormData(previousState => {
      return { ...previousState, email: e.target.value }
    })
  }

Here, we have declared two functions to store name and email data. If we look closer at each one of the functions, we can see that inside the setState() function, we have declared an anonymous function with a parameter. And returning an object that contains the data of the parameter and the data that we want to update. Now, why is that? why bother a function inside setState() function?

You see, when we will set these functions in an onChange() event into the input fields, this state value will change with each keystroke. So do the properties that the state has. Without declaring an anonymous function, sometime it might cause an error while updating the state. But with the help of the anonymous function, react will only run this anonymous function. Not the properties which are inside of this function. That parameter will have all the properties that the state has. It will change accordingly. Hence it will solve the problem.

  • Declare onChange() event handler to each input field and pass the functions that we have declared accordingly as value to those onChange() handler.
// src/App.js

import React, { useEffect, useState } from "react";

function App() {
  const [formData, setFormData] = useState({
    name: "",
    email: ""
  });

  // function for store name
  const handleNameChange = e => {
    setFormData(previousState => {
      return { ...previousState, name: e.target.value }
    })
  }
  // function for store email
  const handleEmailChange = e => {
    setFormData(previousState => {
      return { ...previousState, email: e.target.value }
    })
  }
  return (

    <div className=" flex justify-center lg:h-screen items-center">
      <div className="card w-full md:w-96 items-center shadow-2xl bg-base-100">
        <form className="card-body w-full lg:w-96">
          <div className="form-control">
            <label className="label">
              <span className="label-text">Name</span>
            </label>
            <input onChange={handleNameChange}
              type="text" placeholder="name" className="input input-bordered" />

          </div>

          <div className="form-control">
            <label className="label">
              <span className="label-text">Email</span>
            </label>
            <input onChange={handleEmailChange}
              type="email" placeholder="email" className="input input-bordered" />

          </div>

          <div className="form-control mt-6">
            <button type="submit" className="btn btn-primary">Check Data</button>
          </div>

        </form>



      </div>
    </div>
  );

}

export default App;
  • Console.log the state variable to see the changes in the browser dev tools.
console.log(formData);

As we can see, the changes can be visible as we add or remove any characters in the input fields.

This is how we can update the state that might depend on the previous one.