繁体   English   中英

为什么每个状态钩子更新都会导致异步代码中的单独重新渲染?

[英]Why does each state hook update cause a separate re-render in asynchronous code?

一个组件中使用了两个useState钩子。 如果我们允许事件循环在修改状态之前“重排”,则每个钩子都会导致单独的重新渲染。

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

export default function App() {
  const [foo, setFoo] = useState("initial_foo");
  const [bar, setBar] = useState("initial_bar");

  const onAction = useCallback(async () => {
      await sleep(0); // this is the culprit
      setFoo("updated_foo");
      setBar("updated_bar");
  }, []);

  console.log(`rendering foo:${foo} bar:${bar}`);

  return (
    <>
      <button onClick={onAction}>run test</button>
      <div>{"foo: " + foo}</div>
      <div>{"bar: " + bar}</div>
    </>
  );
}

带有await sleep(0)控制台输出:

rendering foo:initial_foo bar:initial_bar
rendering foo:updated_foo bar:initial_bar
rendering foo:updated_foo bar:updated_bar

如果我们删除await sleep(0); ,一切都按预期工作: setFoosetBar会导致一次重新渲染。

没有await sleep(0)控制台输出:

rendering foo:initial_foo bar:initial_bar
rendering foo:updated_foo bar:updated_bar

演示(在演示控制台输出是重复的,因为它开启了 React 严格模式)

  • 为什么会发生?
  • 这是一个错误还是一个功能?
  • 我们如何防止这种中间重新渲染?

更新:

问题已在React 项目存储库中创建

在承诺(以及与此相关的计时器)中, setState是同步的。 所以,你有两个重新渲染(首先是setFoo ,然后是setBar )而不是组合(批处理)一个。

下面是一个例子:

如果您单击Promise按钮中的setState,您将在每个状态之后重新rerender记录,但如果您单击eventHandler 中的 setState,您将首先获得两个 setState 日志,然后只有一个重新渲染。 这种行为应该在 React 17 中改变,其中状态更新只会是异步的。

 function App() { const [foo, setFoo] = React.useState(); const [bar, setBar] = React.useState(); function handlerPromise() { Promise.resolve().then(() => { console.log("setFoo"); setFoo({}); console.log("setBar"); setBar({}); }) } function handler() { console.log("setFoo"); setFoo({}); console.log("setBar"); setBar({}); } console.log("rerender"); return ( <div> <button onClick={handlerPromise}>setState in Promise</button> <button onClick={handler}>setState in an eventHandler</button> </div> ) } ReactDOM.render(<App/>, document.getElementById("root"))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.development.js"></script> <div id="root"></div>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM