[React 19] Suspense throttling behavior (`FALLBACK_THROTTLE_MS`) kicks in too often
<!-- Please provide a clear and concise description of what the bug is. Include screenshots if needed. Please test using the latest version of the relevant React packages to make sure your issue has not already been fixed. --> React version: 19.0.0 Related Issues: #30408, #31697 This may be the intended behavior, but I'm opening this issue anyway because enough discussion hasn't been done in the related issues IMO and the current behavior still feels poor to me in that it makes it too easy to slow down actual user experience. ## Steps To Reproduce <details> <summary>Code</summary> ```jsx const zero = Promise.resolve(0); function getNumber(num) { return new Promise((resolve) => { setTimeout(() => resolve(num), 100); }); } function App() { const [count, setCount] = useState(zero); const countValue = use(count); useEffect(() => { console.log("countValue =", countValue, Date.now()); }, [countValue]); return ( <button onClick={() => { console.log("click", Date.now()); setCount(getNumber(countValue + 1)); }} > count is {countValue} </button> ); } ``` </details> In short, when a rerendering suspends, you always have to wait for 300ms even if underlying data fetching has finished sooner. In the attached example, when user pushes the button, a new Promise is passed to `use()`, which triggers Suspense. Even though that Promise resolves exactly after 100ms, the UI is updated only after 300ms. I e
Posted by uhyo on Dec 17, 2024, 1:21 PM
Tags
Related issues
- Many devs love to shit on the guy from the 'I just want the exe.
- Now imagine how poor people stress if their smartphone bricks or gets damaged or lost.
- Resuming an extended-thinking session fails permanently with 400 "thinking blocks cannot be modified" (transcript stores thinking text as empty but keeps signat
- I'll preface this with a statement that as a European I want European alternatives to succeed, and MS-owned GitHub to shrivel and disappear.
- Yeah, but there’s a world of difference between “not perfect” and “we rounded a few sliders, and now the modal is a nightmare to use”.
- I used to write a lot of native Windows corporate software in the 90's and 2000's and my standard login window was a floating draggable o...
Raise real-world problems, find people facing the same issue, and discuss solutions.2,000 issues0 comments
reliability (SaaS)
Many devs love to shit on the guy from the 'I just want the exe.
Now imagine how poor people stress if their smartphone bricks or gets damaged or lost.
Resuming an extended-thinking session fails permanently with 400 "thinking blocks cannot be modified" (transcript stores thinking text as empty but keeps signat
I'll preface this with a statement that as a European I want European alternatives to succeed, and MS-owned GitHub to shrivel and disappear.
Yeah, but there’s a world of difference between “not perfect” and “we rounded a few sliders, and now the modal is a nightmare to use”.
I used to write a lot of native Windows corporate software in the 90's and 2000's and my standard login window was a floating draggable o...
App broken with Mosquitto broker 7.0.0
[BUG] Remote Control: automatic reconnection doesn't work -- connection drops silently with no recovery
[React 19] Suspense throttling behavior (`FALLBACK_THROTTLE_MS`) kicks in too often
<!-- Please provide a clear and concise description of what the bug is. Include screenshots if needed. Please test using the latest version of the relevant React packages to make sure your issue has not already been fixed. --> React version: 19.0.0 Related Issues: #30408, #31697 This may be the intended behavior, but I'm opening this issue anyway because enough discussion hasn't been done in the related issues IMO and the current behavior still feels poor to me in that it makes it too easy to slow down actual user experience. ## Steps To Reproduce <details> <summary>Code</summary> ```jsx const zero = Promise.resolve(0); function getNumber(num) { return new Promise((resolve) => { setTimeout(() => resolve(num), 100); }); } function App() { const [count, setCount] = useState(zero); const countValue = use(count); useEffect(() => { console.log("countValue =", countValue, Date.now()); }, [countValue]); return ( <button onClick={() => { console.log("click", Date.now()); setCount(getNumber(countValue + 1)); }} > count is {countValue} </button> ); } ``` </details> In short, when a rerendering suspends, you always have to wait for 300ms even if underlying data fetching has finished sooner. In the attached example, when user pushes the button, a new Promise is passed to `use()`, which triggers Suspense. Even though that Promise resolves exactly after 100ms, the UI is updated only after 300ms. I e
Comments (0)
No comments yet. Start the discussion.