在事件处理程序中进行 setState 调用后,React 何时重新渲染 [英] When does React re-render after a setState call made inside an event handler

查看:36
本文介绍了在事件处理程序中进行 setState 调用后,React 何时重新渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自 React 文档:

From React DOCS:

https://reactjs.org/docs/state-and-lifecycle.html

状态更新可能是异步的

React 可以将多个 setState() 调用批处理为单个更新以提高性能.

React may batch multiple setState() calls into a single update for performance.

这完全有道理.如果你有类似下面的函数,在每个 setState 调用

This makes total sense. If you have something like the function below, it would be very inefficient to re-render on every setState call

const [state1,setState1] = useState(false);
const [state2,setState2] = useState(false);
const [state3,setState3] = useState(false);

function handleClick() {
  setState1(true);
  setState2(true);
  setState3(true);
}

因此,在上述情况下,我希望 React 将所有 3 个 setState 调用批处理为一次重新渲染.而它正是这样做的!

So, in the situation above, I expect React to batch all 3 setState calls into a single re-render. And it does exactly that!

但我想知道的是:

一旦 handleClick 完成,重新渲染是否保证立即 handleClick 运行完成?我的意思是立即,比如立即同步?

Once handleClick has completed, is a re-render guaranteed to happen immediatelly handleClick has done running? I mean literally immediately, like synchronously immediately?

从我构建的这个片段来看,这似乎是真的.handleClick 完成后,React 将同步应用更新(重新渲染).如果我的假设有误,请纠正我.

From this snippet that I've build, it seems that this is true. React will synchronously apply the updates (re-render) after handleClick has completed. Correct me if I'm wrong in assuming that.

见下面的片段:

  • 尽可能快地点击 3 次
  • handleClick 将调用 setState 并记录当前的 props.counter
  • App 上有一个昂贵的循环,所以重新渲染需要很长时间
  • 您将能够比 React 重新渲染整个应用程序的速度快得多
  • 但是你会看到 props.counter 每次都不同,没有任何重复,即使你点击多次真的很快
  • 这意味着一旦你的第二次点击被处理(由于昂贵的循环需要一段时间),React 已经重新渲染了整个事情并且 handleClick 函数已经被重新创建来自 counter 更新状态的 props.counter 的新值.
  • 尝试快速点击 5 次,您会发现行为是相同的.
  • Click 3 times as fast as you can
  • handleClick will call a setState and will log the current props.counter
  • There is an expensive loop on App, so it will take a long time to re-render
  • You'll be able to click much faster than React can re-render the whole App
  • But you'll see the props.counter is different every time, without any repetition, even if you click multiple times really fast
  • It means that once your 2nd click is processed (it will take a while because of the expensive loop), React has already re-rendered the whole thing and the handleClick function has already been recreated with the new value for props.counter that came from the counter updated state.
  • Try clicking 5 times really fast and you'll see that the behavior is the same.

问题

setState 调用在事件处理函数内部进行时,一旦该处理函数完成运行,是否保证在该处理函数完成后立即(同步)进行重新渲染?

When setState calls are made inside an event handler function, once that handler function has completed running, is it guaranteed that a re-render will occur immediately (synchronously) after that completion of the handler?

function App() {
  console.log("App rendering...");
  const [counter, setCounter] = React.useState(0);

  // AN EXPENSIVE LOOP TO SLOW DOWN THE RENDER OF 'App'
  
  for (let i = 0; i < 100000; ) {
    for (let j = 0; j < 10000; j++) {}
    i = i + 1;
  }

  return <Child counter={counter} setCounter={setCounter} />;
}

function Child(props) {
  console.log("Child rendering...");
  
  // THIS FUNCTION WILL CALL 'setState'
  // AND WILL ALSO LOG THE CURRENT 'props.counter'
  
  function handleClick() {
    props.setCounter(prevState => prevState + 1);
    console.log(props.counter);
  }

  return (
    <React.Fragment>
      <div>Counter: {props.counter}</div>
      <button onClick={handleClick}>Click</button>
    </React.Fragment>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

推荐答案

一旦handleClick 完成,重新渲染是否保证立即发生handleClick 运行完成?我的意思是立即,比如立即同步

Once handleClick has completed, is a re-render guaranteed to happen immediatelly handleClick has done running? I mean literally immediately, like synchronously immediately

对于某些事件,包括 click,React 保证组件会在另一个事件发生之前重新渲染.(对于 mousemove 等其他事件,情况并非如此.)您可以找到哪些事件是 这里.当前的术语似乎是 DiscreteEvents 是存在此保证的那些,而 UserBlockingEvents 是不保证它的那些.很可能在当前的实现中,这意味着它在事件处理结束时同步完成¹,但我认为保证没有那么具体.

For certain events, including click, React guarantees that the component will be re-rendered before another event can occur. (This isn't the case for other events like mousemove.) You can find which events are which here. The current terminology seems to be that DiscreteEvents are the ones for which this guarantee exists, and the UserBlockingEvents are the ones for which it isn't guaranteed. It may well be that in the current implementation that means it's done synchronously at the end of the event handling¹, but I think the guarantee is less specific than that.

我从 Dan Abramov 在 Twitter 上了解到这一点(他使用了旧的术语来描述事件).

I learned this from Dan Abramov on Twitter (he used the older terminology for the events).

¹ 事实上,在他的回答中,Joseph D. 指出了Dan Abramov 的评论 说它现在是,但也说这是实现细节,并可能在未来版本中更改".

¹ and in fact, in his answer Joseph D. points to a comment by Dan Abramov saying that it is, for now, but also saying "This is implementation detail and may change in future versions".

这篇关于在事件处理程序中进行 setState 调用后,React 何时重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆