React useState hook - 更新状态时何时使用以前的状态?

IT技术 reactjs react-hooks
2021-05-18 12:55:35

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

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

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

(我可以通过设置一个 setForm 来设置两个字段来使 validate2 工作,但是下面的代码被设计来显示可以调用 setForm 的两种方式的差异,有和没有以前的状态。)

代码沙盒

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个回答

React 文档中,他们提到了以下内容,

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

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

这就是 validate1 起作用的原因,因为对 setForm 的第二次调用取决于之前的 setForm 调用状态,并且如果使用更新函数表单,状态将是最新的。

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

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

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

ReactsetState并且useState不会直接对状态对象进行更改。

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

因此,出于性能原因,更新 React 状态的过程是异步的。这就是为什么感觉变化并不立竿见影的原因。

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