Home > Mobile >  Delay in the state change
Delay in the state change

Time:10-06

When I press "Submit" button the console shows "success" even though the input is empty, and when I press again it finally shows "error".

How do I change the code so that console will show "error" when I press the button for the first time?

import React, { useState } from "react";
import "./App.css";

function App() {
  const [input, setInput] = useState("");
  const [error, setError] = useState(false);
  const submitHandler = (e) => {
    e.preventDefault();
    if (input === "") {
      setError(true);
    }
    if (error === true) {
      console.log("error");
      return;
    }
    console.log("success");
  };
  return (
    <div className="App">
      <form onSubmit={submitHandler}>
        <input onChange={(e) => setInput(e.target.value)}></input>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

export default App;

CodePudding user response:

State change is async, you should check first submit against another state or a reference (useRef).

function App() {
  const [isFirstSubmit, setIsFirstSubmit] = useState(true);

  const submitHandler = (e) => {
    e.preventDefault();

    if (isFirstSubmit) {
      console.log("error");
      setIsFirstSubmit(false);
    }
  };
  return <form onSubmit={submitHandler}>...</form>;
}

CodePudding user response:

Look again at the state declaration:

const [error, setError] = useState(false);

There is no way that calling setError is going to change error, because it's a const. The language doesn't allow it.

What happens is that the useState hook will return the value passed to setError the next time the component renders.

If you adjust your handleSubmit logic a bit, accounting for the fact that it knows when it calls setError(true), you can achieve the desired result:

  const submitHandler = (e) => {
    e.preventDefault();
    if (input === "") {
      setError(true);
      console.log("error");
      return;
    }
    console.log("success");
  };

All I did was remove two lines of code.

CodePudding user response:

Setting the state in React is an async function.
Meaning that the when you set the state and put a console.log right after it, like in your example, the console.log function runs before the state has actually finished updating.

Which is why we have useEffect, a built-in React hook that activates a callback when one of it's dependencies have changed.
Like so:

import { useState, useEffect } from 'react';

const [state, setState] = useState();

useEffect(() => {
   // Actions we want to happen when the state has been fully updated.
}, [state]);

For your example, it can look like this:

const submitHandler = (e) => {
   e.preventDefault();
   if (input === "") {
     setError(true);
   }
}

useEffect(() => {
   // No need for === true
   if (error) {
     console.log("error");
     return;
   }
   console.log("success");
}, [error])

CodePudding user response:

You can update your code to

if (input === "") {
  setError(true);
  console.log("error");
  return;
}

console.log("success");

So in first if you can handle error condition where after it will be success.

  • Related