React SetState需要200ms+

发布于 2025-02-06 07:41:10 字数 1449 浏览 2 评论 0原文

我正在听一个Websocket触发每秒一次回调的Websocket:

SetState1每秒发生,SetState2也会在10秒后每秒发生,并允许largechildcomponent 显示。

我发现更新此状态的时间超过200ms。

const myWebsocketCallback = async(newData) => {
  dataRef.current = [...dataRef.current, newData]

  const start = performance.now()
  setDataState(dataRef.current)
  console.log('setState', performance.now() - start)

  doWorkWithNewData()
}

因此,设置状态最初很慢,并且当largechildComponent呈现时,设置状态也很慢。


我发现将大型JSON对象从状态初始化转移到Initeffect()大大减少了这段时间。

- const [myBigData, setMyBigData] = useState(VERY_LARGE_JSON_OBJECT)

+ const [myBigData, setMyBigData] = useState()
+ useEffect(() => {
+   setMyBigData(VERY_LARGE_JSON_OBJECT)
+ }, [])

是否检查了每个渲染的默认状态值?我是否应该在使用效率(myfunc,[])中初始化状态?


仅上述变化就取得了巨大改进。

但是,setState()仍在进行80ms+,并且似乎取决于渲染的大小(子组件)。

我的印象是setState()async任务,无论依赖于此,都应该快速执行。

为什么还需要80ms才能更新状态?

是由于在回调功能中吗?州真的在等孩子渲染吗?

I'm listening to a websocket which triggers a callback once per second:

setState1 happens every second, setState2 also happens every second after 10 seconds and allows LargeChildComponent to display.

I found that updating this state was taking over 200ms.

Slow setState console logs and Performance tab

const myWebsocketCallback = async(newData) => {
  dataRef.current = [...dataRef.current, newData]

  const start = performance.now()
  setDataState(dataRef.current)
  console.log('setState', performance.now() - start)

  doWorkWithNewData()
}

So setting state was slow initially, and is extra slow when LargeChildComponent is rendering.


I found that moving a large JSON object from a state initialization to a init useEffect() reduced that time greatly.

- const [myBigData, setMyBigData] = useState(VERY_LARGE_JSON_OBJECT)

+ const [myBigData, setMyBigData] = useState()
+ useEffect(() => {
+   setMyBigData(VERY_LARGE_JSON_OBJECT)
+ }, [])

Faster setState console logs and Performance tab

Is default state value checked every render? Should I be initializing state in a useEffect(myFunc, [])?


The above change alone made a MASSIVE improvement.

However, that setState() is still taking 80ms+, AND it seems to be dependent on the size of the render (child components).

I was under the impression that setState() is an async task and should happen quickly regardless of any components which depend on it.

Why is it still taking 80ms to update state?

Is it due to being inside a callback function? Does state actually wait for children to render?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

羁拥 2025-02-13 07:41:10

每当您在React Lifecycle方法之外调用SetState(React事件处理程序或渲染功能或效果),则它倾向于 block ,而React重新呈现所有内容。在React 18中,他们正在改变状态变化和渲染的方式。

您可以:

更新到React 18 Creatoot以获取自动批处理


import ReactDOM from "react-dom";
import App from 'App';

const container = document.getElementById('root');

// Create a root.
const root = ReactDOM.createRoot(container);

// Initial render
root.render(<App name="Saeloun blog" />);

// During an update, there is no need to pass the container again
root.render(<App name="Saeloun testimonials" />);

或使用React&lt中的unstable_batchupdate方法; 18

import { unstable_batchedUpdates } from 'react-dom'

const myWebsocketCallback = async(newData) => {
  dataRef.current = [...dataRef.current, newData]

  const start = performance.now()
  unstable_batchUpdates(() => {
    setDataState(dataRef.current)
  })
  console.log('setState', performance.now() - start)

  doWorkWithNewData()
}


anytime you call setState outside of a React lifecycle method (React event handler or render function or effect) then it tends to block while React re-renders everything. In React 18 they are making changes to the way state changes and renders are batched.

You can either:

Update to React 18 createRoot to get automatic batching


import ReactDOM from "react-dom";
import App from 'App';

const container = document.getElementById('root');

// Create a root.
const root = ReactDOM.createRoot(container);

// Initial render
root.render(<App name="Saeloun blog" />);

// During an update, there is no need to pass the container again
root.render(<App name="Saeloun testimonials" />);

or use the unstable_batchUpdate method in React < 18

import { unstable_batchedUpdates } from 'react-dom'

const myWebsocketCallback = async(newData) => {
  dataRef.current = [...dataRef.current, newData]

  const start = performance.now()
  unstable_batchUpdates(() => {
    setDataState(dataRef.current)
  })
  console.log('setState', performance.now() - start)

  doWorkWithNewData()
}


~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文