From a07117c938afe3a231ac90c6804cfc13deae8b13 Mon Sep 17 00:00:00 2001 From: abaevbog Date: Wed, 10 Jul 2024 22:18:25 -0700 Subject: [PATCH] Patch react-virtualized to fix react 18 scroll lag (#4370) React 18 introduced automatic batching which tries to avoid unnecessary re-rendering (https://react.dev/blog/2022/03/08/react-18-upgrade-guide#automatic-batching). In some components based on react-virtualized (e.g. tag selector), it leads to visible lagginess on scroll via keypress or mouse wheel (not trackpad). This patch wraps setState of the scroll handler of react-virtualized with ReactDOM.flushSync, which opts out of automatic batching. Fixes: #4368 --- js-build/babel-worker.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/js-build/babel-worker.js b/js-build/babel-worker.js index 32605633a5..d42054066f 100644 --- a/js-build/babel-worker.js +++ b/js-build/babel-worker.js @@ -46,6 +46,16 @@ async function babelWorker(ev) { transformed = contents.replace('scrollDiv = document.createElement("div")', 'scrollDiv = document.createElementNS("http://www.w3.org/1999/xhtml", "div")') .replace('document.body.appendChild(scrollDiv)', 'document.documentElement.appendChild(scrollDiv)') .replace('document.body.removeChild(scrollDiv)', 'document.documentElement.removeChild(scrollDiv)'); + // React 18: wrap setState in onScroll handler with ReactDOM.flushSync to avoid + // automatic batching https://react.dev/blog/2022/03/08/react-18-upgrade-guide#automatic-batching + // which causes less frequent re-rendering and lagginess on scroll of components such as tag selector + let onScrollSetStateChunkRegex = /(_this\.state\.isScrolling\s*\|\|\s*isScrollingChange\(!0\),\s*)(_this\.setState\s*\(\s*\{[^}]*\}\s*\))/; + if (!onScrollSetStateChunkRegex.test(transformed)) { + throw new Error(`"_this.state.isScrolling || isScrollingChange(!0), _this.setState({" not found in react-virtualized`); + } + transformed = transformed.replace(onScrollSetStateChunkRegex, (_, p1, p2) => { + return `${p1}ReactDOM.flushSync(() => ${p2.trim()})`; + }); } // Patch single-file else if (sourcefile === 'resource/SingleFile/lib/single-file.js') {