当前位置: 首页 > 面试题库 >

React是否保持状态更新的顺序?

长孙沈义
2023-03-14
问题内容

我知道React可以异步并批量执行状态更新以优化性能。因此,在调用之后,您将永远无法相信要更新的状态setState。但是你可以信任的反应
更新相同的顺序状态setState被称为

  1. 相同的组件?
  2. 不同的组件?

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

1. 在以下情况下,是否有可能 a为假而b为真

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为假而b为真

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是否有明确定义的方式来执行这些状态更新感兴趣,仅此而已。

非常感谢文档支持的任何答案。


问题答案:

我在做React。

TLDR:

但是你可以相信React可以按照要求setState的顺序更新状态吗

  • 相同的组件?

是。

  • 不同的组件?

是。

订单 的更新总是尊重。是否在它们之间看到中间状态取决于您是否在批处理中。

当前(React 16和更早版本), 默认情况下仅批处理React事件处理程序中的更新
。有一个不稳定的API可以在极少数情况下在需要时强制在事件处理程序之外进行批处理。

在未来的版本中(可能是React
17及更高版本),React默认会批处理所有更新,因此您不必考虑这一点。与往常一样,我们将在React博客和发行说明中宣布有关此更改的信息。

理解这一点的关键是, 无论setState()在React事件处理程序中
执行了多少个组件中的多少次调用,它们都将在事件结束时仅产生一次重新渲染
。这对于大型应用程序性能良好至关重要的,因为如果ChildParent每个呼叫setState()处理click事件的时候,你不想再渲染Child两次。

在您的两个示例中,setState()调用都在React事件处理程序中进行。因此,它们总是在事件结束时一起刷新(并且您看不到中间状态)。

更新总是 按照发生的顺序进行浅层合并 。因此,如果第一个更新为{a: 10},第二个为{b: 20},第三个为{a: 30},则呈现状态将为{a: 30, b: 20}。对同一状态键的更新(例如,a在我的示例中)总是“获胜”。

this.state当我们在批处理结束时重新呈现UI时,将更新该对象。因此,如果您需要根据先前的状态(例如增加计数器)来更新状态,则应使用setState(fn)为您提供先前状态的功能版本,而不是从中读取this.state

在您的示例中,我们看不到“中间状态”,因为我们位于启用批处理 的React事件处理程序 中(因为退出事件时React知道)。

但是,在React 16和早期版本中,默认情况下,在React事件处理程序外部都没有批处理。因此,如果在您的示例中,我们使用AJAX响应处理程序代替handleClicksetState()则会在发生时立即对其进行处理。在这种情况下,是的,您
看到一个中间状态:

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
});

我们意识到, 根据您是否在事件处理程序,行为会有所不同,这很不方便
。这将在以后的React版本中更改,该版本将默认批处理所有更新(并提供选择加入的API以同步刷新更改)。在我们切换默认行为(可能在React 17中)之前,
有一个可用于强制批处理的API

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
});

内部所有React事件处理程序都被包装,unstable_batchedUpdates这就是为什么它们默认情况下被批处理的原因。请注意,将更新打包unstable_batchedUpdates两次是无效的。当我们退出最外部的unstable_batchedUpdates调用时,将刷新更新。

该API是“不稳定的”,即默认情况下启用批处理后我们将其删除。但是,我们不会在次要版本中删除它,因此在某些情况下,如果需要在React事件处理程序之外强制进行批处理,则可以放心地依赖它,直到React
17。

总而言之,这是一个令人困惑的话题,因为默认情况下,React仅在事件处理程序中进行批处理。这将在将来的版本中更改,并且行为将变得更加简单。但是解决方案不是
少批处理 ,而是默认情况下 多批处理 。那就是我们要做的。



 类似资料:
  • 我知道React可能会异步和批量地执行状态更新,以进行性能优化。因此,在调用之后,您永远不能相信会更新状态。但是,您是否信任React按照调用时的顺序更新状态 相同的组件? 不同的组件? 任何有文档支持的答案都是非常感谢的。

  • 我试图将“加载”的状态从true更改为false,但当我调用一个函数并在该函数中设置“this.setState({loading:false})”时,加载状态仍然保持true。 在下面的代码中,当按钮按钮函数被调用时,它将“加载”状态设置为真,但当用户成功登录“加载”状态时,应该变为假,这样我的渲染按钮函数将重新渲染,旋转器可以隐藏自己并显示按钮。 为什么LoginSAccess函数中的“加载”

  • 所以我有这个: 只是一个数组的数字例如然而没有给出正确的总数,但?我甚至放了一个超时延迟,看看这是否解决了问题。任何明显的还是我应该发布更多的代码?

  • 问题内容: 以下代码以相同的插入顺序为我提供了输出。我阅读了Javadoc,他们甚至没有谈论插入顺序。有人可以帮助我获取正确的信息。 问题答案: 不,不是的。要保留插入顺序,请改用(javadoc)。 而且,现在优先于,因为它具有不必要的并发开销。(请参见HashMap和Hashtable之间的区别?。)

  • HTTP协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态 客户端与服务器端的一次通信,就是一次会话 实现状态保持的方式:在客户端或服务器端存储与会话有关的数据 存储方式包括cookie、session,会话一般指session对象 使用cookie,所有数据存储在客户端,注意不要存储敏感信息 推荐使用sesison方式,所有数据存储在服务器端,在客户端cookie中存储sessio

  • 技术栈是 react + antd@4 + antd-procomponents 如何实现动态表单。 目前我尝试了如下方案,均不可以 valueschange 实时更新,因为数据结构对不上,所以在覆盖的时候会有部分数据覆盖异常 ref 读取,因为表单是渲染出来的,所以 ref 被覆盖了,只有最后一个。 ref 读取,不知道是不是因为手风琴效果,导致没点开的表单数据是无法获取的。