反应useState钩-更新状态时何时使用先前状态?

时间:2020-08-22 22:44:51

标签: reactjs react-hooks

在下面的代码中,除非我将先前的状态传递给状态设置调用(“ setForm”),否则表单无法正确更新。

要查看其运行效果,请按原样运行代码,控制台将显示“ true”,表明它可以正常工作。那是使用'validate1'函数。如果将其替换为“ validate2”(不使用以前的状态),它将无法打印“ true”。

似乎在validate2中,由于这些调用的异步特性,第二个setForm调用将覆盖第一个setForm调用的form.long状态。但是validate1为什么起作用?为什么使用以前的状态会导致它起作用?任何有关此行为的文档都将非常有帮助。

(我可以通过使用一个设置两个字段的setForm来使validate2起作用,但是下面的代码旨在显示在调用setForm的两种方式中(带有或不带有先前状态)有所不同。)

CodeSandbox

const {useState, useEffect} = React;


function LoginForm() {
  const [form, setForm] = useState({
    username: "",
    password: "",
    long: null
  });

  useEffect(() => {
    console.log(form.long);
  }, [form.long]);

  const validate1 = (e) => {
    e.preventDefault();
    setForm((prevState) => ({
      ...prevState,
      long: form.password.length >=3 ? true : false
    }));
    setForm((prevState) => ({
      ...prevState,
      username: "*****"
    }));
  };

  const validate2 = (e) => {
    e.preventDefault();
    setForm({
      ...form,
      long: form.password.length >=3 ? true : false
    });
    setForm({
      ...form,
      username: "*****"
    });
  };

  const updateField = (e) => {
    setForm({
      ...form,
      [e.target.name]: e.target.value
    });
  };

  return (
    <form onSubmit={validate1}>
      <label>
        Username:
        <input value={form.username} name="username" onChange={updateField} />
      </label>
      <br />
      <label>
        Password:
        <input
          value={form.password}
          name="password"
          type="password"
          onChange={updateField}
        />
      </label>
      <br />
      <button>Submit</button>
    </form>
  );
}


// Render it
ReactDOM.render(
  <LoginForm/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

2 个答案:

答案 0 :(得分:0)

为什么validate1可以工作?为什么使用以前的状态会导致它起作用?

setForm({
  ...form,
  long: form.password.length >=3 ? true : false
});
setForm({
  ...form,
  username: "*****"
});

第二个formsetForm的值仍然是旧值,直到下一次重新渲染为止。它不反映从先前的form起更新的setForm

反应setStateuseState不会直接对状态对象进行更改。

setStateuseState为React核心创建队列以更新React组件的状态对象。

因此出于性能原因,更新React状态的过程是异步的。这就是为什么更改不会立即生效的原因。

https://linguinecode.com/post/why-react-setstate-usestate-does-not-update-immediately

答案 1 :(得分:0)

React documentation中,他们提到以下内容,

如果下一个状态取决于当前状态,我们建议使用 更新器函数形式,而不是:

this.setState((state) => {
  return {quantity: state.quantity + 1};
});

这是validate1起作用的原因,因为对setForm的第二次调用取决于先前的setForm调用状态,并且如果使用了updater函数形式,则该状态将是最新的。