我知道React可以异步和批量执行状态更新,以优化性能.因此,在调用setState之后,您永远不能相信状态会被更新.但你能相信我对update the state in the same order as 100 is called的react 吗

  1. 同一个组件?
  2. 不同的组件?

考虑单击以下示例中的按钮:

1..a is false and b is true是否有可能:

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { a: false, b: false };
  }

  render() {
    return <Button onClick={this.handleClick}/>
  }

  handleClick = () => {
    this.setState({ a: true });
    this.setState({ b: true });
  }
}

2..a is false and b is true是否有可能:

class SuperContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { a: false };
  }

  render() {
    return <Container setParentState={this.setState.bind(this)}/>
  }
}

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { b: false };
  }

  render() {
    return <Button onClick={this.handleClick}/>
  }

  handleClick = () => {
    this.props.setParentState({ a: true });
    this.setState({ b: true });
  }
}

请记住,这些都是对我的用例的极端简化.我意识到我可以用不同的方式来实现这一点,例如,在示例1中同时更新两个状态参数,以及在示例2中对第一个状态更新的回调中执行第二个状态更新.然而,这不是我的问题,我只感兴趣的是,是否有一种定义良好的方式来执行这些状态更新,而不是别的.

任何有文档支持的答案都将不胜感激.

推荐答案

我在做React.

TLDR:

但是,您能信任React以调用setState的相同顺序更新状态吗

  • 同一个组件?

  • 不同的组件?

order次更新始终受到尊重.你是否看到它们之间的中间状态取决于你是否在一个批次中.

目前(React 16及更早),only updates inside React event handlers are batched by default.有一个不稳定的API,当您需要时,它可以在事件处理程序之外强制批处理罕见的情况.

在future 的版本(可能是React 17及更高版本)中,React将默认批处理所有更新,因此您无需考虑这一点.一如往常,我们将在React blog和发行说明中宣布有关此的任何更改.


理解这一点的关键是no matter how many 100 calls in how many components you do inside a React event handler, they will produce only a single re-render at the end of the event.这对于大型应用程序的良好性能至关重要,因为如果ChildParent在处理单击事件时都调用setState(),则不希望重新渲染Child两次.

在这两个示例中,setState()个调用都发生在React事件处理程序中.因此,它们总是在事件结束时一起刷新(而你看不到中间状态).

更新总是shallowly merged in the order they occur.因此,如果第一次更新为{a: 10},第二次更新为{b: 20},第三次更新为{a: 30},则渲染状态将为{a: 30, b: 20}.对同一状态密钥的最新更新(如我的示例中的a)总是"赢".

当我们在批处理结束时重新呈现UI时,this.state对象将被更新.因此,如果需要基于以前的状态更新状态(例如递增计数器),应该使用提供以前状态的函数setState(fn)版本,而不是从this.state读取.如果你对这其中的原因感到好奇,我会详细解释.


在您的示例中,我们看不到"中间状态",因为我们inside a React event handler岁时启用了批处理(因为React"知道"我们何时退出该事件).

然而,在React 16和更早的版本there is yet no batching by default outside of React event handlers中.因此,如果在您的示例中,我们有一个AJAX响应处理程序,而不是handleClick个,那么每个setState()个响应处理程序都会在发生时立即被处理.在这种情况下,可以看到一种中间状态:

promise.then(() => {
  // We're not in an event handler, so these are flushed separately.
  this.setState({a: true}); // Re-renders with {a: true, b: false }
  this.setState({b: true}); // Re-renders with {a: true, b: true }
  this.props.setParentState(); // Re-renders the parent
});

我们意识到这很不方便.这将在future 的React版本中更改,该版本将默认批处理所有更新(并提供一个opt-in API以同步刷新更改).直到我们切换默认行为(可能在React 17中),there is an API you can use to force batching:

promise.then(() => {
  // Forces batching
  ReactDOM.unstable_batchedUpdates(() => {
    this.setState({a: true}); // Doesn't re-render yet
    this.setState({b: true}); // Doesn't re-render yet
    this.props.setParentState(); // Doesn't re-render yet
  });
  // When we exit unstable_batchedUpdates, re-renders once
});

Internal React事件处理程序都被包装在unstable_batchedUpdates中,这就是默认情况下批处理它们的原因.请注意,在unstable_batchedUpdates中包装更新两次没有效果.当我们退出最外层的unstable_batchedUpdates次呼叫时,更新会刷新.

该API是"不稳定的",因为在默认情况下,当批处理已经启用时,我们将删除它.但是,我们不会在次要版本中删除它,因此,如果在某些情况下需要在React事件处理程序之外强制批处理,您可以在React 17之前安全地依赖它.


总而言之,这是一个令人困惑的话题,因为默认情况下,只在事件处理程序中进行批处理.这将在future 的版本中发生变化,届时行为将更加简单.但解决方案不是batch less,而是默认为batch more.这就是我们要做的.

Reactjs相关问答推荐

运行 node server.js会导致以下错误:Route.post()需要回调函数,但在Route.&处得到了[对象Undefined] lt;计算>

ReferenceError:未在Redux组件中定义窗口

如何在Reac.js中通过子组件和props 调用父组件函数?

如何在react 流中使用文本区域和改变 node 的输入大小?

Redux Store未触发React组件中的重新呈现

React中的useEffect钩子

ReactJS:唯一项目的数量总和

未定义发送的数据无法在reactjs中找到原因

点击页脚链接时,如何更改ReactJS导航栏中的活动菜单项(样式为Tailwind CSS)?

React Todo List 应用程序我在实现删除功能时遇到问题

从 MongoDB createAt 字段中分割精确时间

通过createRoot创建的React元素无法调用Provider值

无法使用react-hook-form和react-places-autocomplete在字段中输入值

在一个事件处理程序中进行多次调度是个好主意吗?

Material UI v5.11 - Prop sx 在响应式中写了两次

响应式媒体 React Tailwind

使用输入类型文本对 useState 和日期做出react

将 dict 值转换并插入到react 钩子的列表中

设置 Material UI 表格默认排序

如何在组件文件夹内的react 组件文件中导入外部css文件?