繁体   English   中英

在 useEffect 中使用 flushSync() 是否和使用 useLayoutEffect 一样?

[英]With flushSync() inside useEffect do we do the same as using useLayoutEffect?

https://reactjs.org/docs/react-dom.html#flushsync

强制 React同步刷新提供的回调中的任何更新。 这确保了 DOM 立即更新。

// Force this state update to be synchronous.
flushSync(() => {
  setCount(count + 1);
});
// By this point, DOM is updated.

知道了,这和使用useLayoutEffect是一样的,还是我理解错了 flushSync()

const App = () => {
    const [name, setName] = React.useState("Leonardo");
    React.useEffect(() => {
        ReactDOM.flushSync(() => {
            for (let index = 1; index <= 100000; index++) { // for simulate blocking
                console.log(index);
            }
            setName("Jose");
        });
    });
    return (
        <div>
            <h1>Hello {name}</h1>
        </div>
    );
};

跟这个一样吗?

React.useLayoutEffect(() => {
  for (let index = 1; index <= 100000; index++) {
   console.log(index);
  }
  setName("Jose");
});

useLayoutEffect 对于在绘制 dom 之前或代码导致闪烁时需要发生的事情很有用。 它已经是同步的,并且总是在代码中的每个 useEffect 挂钩之前执行。

flushSync 用于将 setState 转换为同步。 在 99% 的情况下,您将在表单提交处理程序之类的处理程序中使用 flushSync,在 useEffect 之外执行命令式操作

function handleSubmit(values) {
  flushSync(() => {
   setForm(values);
  });
}

请注意 flushSync 会强制重新渲染,因此请谨慎使用

flushSync 的常见用例是在设置 state 后立即更新 DOM。 示例滚动到列表中新添加的元素

 flushSync(() => {
   setElements((elements) => [
    ...elements,
    {
      id: 'random',
    },
   ]);
 });
 // scroll to element here

检查此示例https://codesandbox.io/s/react-18-batching-updates-flushsync-forked-vlrbq8 您可以删除 flushSync 并查看差异

flushSync用于强制 React 刷新 state 更新,当您尝试将它放在useEffect中时,它不会影响调用useEffect的时间,它总是更改反映在浏览器上之后,而useLayoutEffect在之前和之前调用这是它们之间的主要区别。

所以flushSync不是应该在 useEffect 中执行的useEffect你甚至会收到这个警告

警告:从生命周期方法内部调用了 flushSync。 当 React 已经呈现时,React 无法刷新。 考虑将此调用移至调度程序任务或微任务。

他们不一样。 您的代码可能提供相同的性能、功能和结果,但它们在本质上是不同的。 flushSync是一个低级别的 API,它绕过正常的调度机制立即将更新刷新到 React DOM。 它应该谨慎使用并且只在必要时使用,因为它会导致性能不佳并且更容易出现错误和不一致。 另一方面, useLayoutEffect是一个更高级别的挂钩,它安排 DOM 更新在处理完所有其他更新后同步发生。 它通常是确保更新与页面布局同步的首选方法。

我做了这段代码,看看我是否理解了一切,请纠正我:

function App2() {
    const [c, setC] = React.useState(0);
    const inc1 = () => {

      /*setC is asynchronous (withoutFlushSync), so it continues the 
      code downwards and therefore from the DOM it 
      brings us the value without increment in 1*/
      setC((c) => c + 1);

      console.log(document.getElementById("myId").innerText); // old value from DOM
      console.log(c); // However below log will still point to old value ***BECAUSE OF CLOSURE***
    };

    const inc2 = () => {
      /*waits until the DOM is modified with the new state (in the first click
      c = 1)*/
      ReactDOM.flushSync(() => { // Wait
        setC((c) => c + 1);
      });

      /* brings the c = 1 of the DOM because it waited until the DOM 
      was modified with the new state incremented by one. */
      console.log(document.getElementById("myId").innerText); // new value from DOM 

      console.log(c); // However below log will still point to old value ***BECAUSE OF CLOSURE***
    };
    return (
      <div className="App">
        Count: <div id="myId">{c}</div>
        <button onClick={inc1}>without flushSync</button>
        <button onClick={inc2}>with flushSync</button>
      </div>
    );
  }
暂无
暂无

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

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