React state 更新原理(二) - state 随时间的变化

518 阅读2分钟

这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战

翻译自:beta.reactjs.org/learn/state…

state 变量可能看起来像您可以读取和写入的常规 JavaScript 变量。但是,state 的行为更像是快照。设置它不会更改您已有的 state 变量,而是会触发重新渲染。

这个系列的文章你将学习到:

  • 如何设置 state 的触发器进行重新 render
  • state 何时以及如何更新
  • 设置 state 后为什么状态不会立即更新
  • 事件处理程序如何访问 state 的“快照”

系列文章

state 随时间的变化

来看一些有趣的问题,试着猜一下点击按钮会提示什么:

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        alert(number);
      }}>+5</button>
    </>
  )
}

如果使用之前的方法,您可以猜测出 alert 显示为“0”:

setNumber(0 + 5);
alert(0);

但是如果你把一个计时器放在 alert 上,让它只在组件重新渲染后触发呢?它会说“0”还是“5”?猜一猜吧!

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        setTimeout(() => {
          alert(number);
        }, 3000);
      }}>+5</button>
    </>
  )
}

惊讶吗?如果替换方法中的变量,可以看到传递给 alert 的是 state 的“快照”!

setNumber(0 + 5);
setTimeout(() => {
  alert(0);
}, 3000);

React 中存储的 state 可能在 alert 的运行时已更改,但它使用的是用户与其交互时的 state 快照!

state 变量的值在 render 中永远不会改变,即使它的事件处理程序的代码是异步的。在 render 的 onClick 中,即使在 setNumber(number + 5) 被调用之后,number 的值仍然是 0。当 React 通过调用您的组件“获取 UI 的快照”时,它的值是“固定的”。

下面是一个示例,说明如何使你的事件处理程序更不容易出现计时错误。下面是一个发送消息延迟五秒的表单。想象一下这个场景:

  1. 你按下“Send”按钮,向 Alice 发送“Hello”。
  2. 在五秒延迟结束之前,您将“To”字段的值更改为“Bob”。

您希望显示什么?它会显示“You said Hello to Alice”吗?或者它会显示“You said Hello to Bob”?根据您所知道的进行猜测,然后尝试:

import { useState } from 'react';

export default function Form() {
  const [to, setTo] = useState('Alice');
  const [message, setMessage] = useState('Hello');

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`You said ${message} to ${to}`);
    }, 5000);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        To:{' '}
        <select
          value={to}
          onChange={e => setTo(e.target.value)}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">Send</button>
    </form>
  );
}

React 在一个渲染的事件处理程序中保持 state 值“固定”。在代码运行时,您不需要担心 state 是否发生了变化。

但是,如果您想在重新渲染之前读取最新状态怎么办?您将需要使用状态更新程序功能,可以在这里找到答案