my understanding is that flushSync does a synchronous force reflow but not a repaint of the screen. So in the following snippet (taken from the github discussion), we can get the correct style info based on the updated state value c after the first flushSync call, however, the change is not visible yet. React provides no way to repaint the screen. It only mutates the DOM and It's browsers that decide when to repaint. Is my understanding correct? Thank you!
import { useState } from 'react';
import { flushSync } from 'react-dom';
function App() {
const [count, setCount] = useState(0);
const [flag, setFlag] = useState(false);
function handleClick() {
flushSync(() => {
setCount(c => c + 1);
});
// React has updated the DOM by now
flushSync(() => {
setFlag(f => !f);
});
// React has updated the DOM by now
}
return (
<div>
<button onClick={handleClick}>Next</button>
<h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
</div>
);
}
Update:
@JaredSmith made a comment that browser will undoubtedly paint in between the two flushSync. I did an experiment to verify that but the experiment actually suggests that the browser will not paint between the two flushSync. In the following code, I inserted a loop which runs for 20s after the first flushSync. What I see is that val: 0 is first rendered, and then after 20s, val: 2. The intermediate val: 1 is never painted to the screen. This experiment indicates that there is no repaint between the two flushSync.
Based on the experiment result, I suspect that the browser (Chrome) intentionally avoids repaint until a function completes its execution (even though I cannot find a spec for that).
import React, { useEffect, useLayoutEffect, useState } from 'react';
import { flushSync } from 'react-dom';
function App() {
const [val, setVal] = React.useState(0);
useEffect( ()=> {
setTimeout(() => {
console.debug("first flushSync starts.");
flushSync(setVal((v) => v + 1));
console.debug('about to start loop');
const st = Date.now();
var et;
var diff;
do {
et = Date.now();
diff = Math.floor((et - st) / 1000);
} while (diff < 20);
console.debug("loop end");
flushSync(setVal((v) => v + 1));
});
return;
}, []);
return (<div>
val: { val }
</div>);
}