DEV Community

Cover image for Have you used `flushSync` in React?

Have you used `flushSync` in React?

Som Shekhar Mukherjee on December 23, 2021

In this post we'll discuss about the flushSync utility provided by react-dom. Let's try and understand what flushSync is and how it can useful thr...
Collapse
 
mohithgupta profile image
K.Mohith Gupta

Why dont you just use

setTimeout(()=> { listRef.current.scrollTop = listRef.current.scrollHeight;
}, 100)

Is this bad or any complications involved?

Collapse
 
somshekhar profile image
Som Shekhar Mukherjee

I don't see a reason why you would want to use setTimeout, this clearly a side effect and there are better options to handle side effects in React.

And also how would you know what the exact timeout value should be? Let's say if you choose 100ms (as mentioned in your example) and React does all the state update in 5ms, then the user of your app has to wait for 95ms (which is unnecessary) and suppose React takes 200ms then the whole purpose of using setTimeout gets nullified.

I've also elaborated the "Using effect hook" section, you might want to give it a read again.

Collapse
 
mohithgupta profile image
K.Mohith Gupta

Ok Bro, Why so serious. I'm a beginner! I just asked a doubt there!!
Thanks for your response though!

One more doubt I've got here, Can we use async on functoin and await on the
setTimeout(()=> { listRef.current.scrollTop = listRef.current.scrollHeight;
}, 100)

line?
Would that work? If yes, is this considered a bad practice?

Thread Thread
 
somshekhar profile image
Som Shekhar Mukherjee • Edited

No no, you got me wrong, I didn't mean to be rude, I was just trying to answer your question.

Event handlers can be async functions, no problem in that, but setTimeout doesn't return a promise so there's no point of using an await with it (setTimeout returns the timer ID which you can use to clear the timeout).

Example below shows an async handler:

const sleep = (time) =>
  new Promise((res) => setTimeout(res, time));

function Example() {
  const handleClick = async () => {
    await sleep(2000);
    console.log("button clicked");
  };

  return <button onClick={handleClick}>Click me</button>;
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
mohithgupta profile image
K.Mohith Gupta

No, I meant is it ok to have the code like this :

const onAdd = async (newTask) => {

await setTodos([...todos, { id: uuid(), task: newTask }]);

listRef.current.scrollTop = listRef.current.scrollHeight;
};

then the scrolling will wait till the settodo is done rght? or am I wrong?

Collapse
 
technikhil314 profile image
technikhil314

Thats actually bad but not too bad cause you are not mutationg dom tree. Assume you are mutating dom tree in setimeout then it would have became worst.
Also settimeout is not guaranteed to run exactly after 100ms it may drift all the way beyond 300ms mark (minimal threshhold to show feedback to user of their action) which would irritate user. Try putting a long empty loop after setTimeout and you can see that happening.

Collapse
 
wasim1312 profile image
wasim • Edited

const cancel = () => {
flushSync(() => {
changeModalRef.current?.close();
});

flushSync(() => {
  cancelModalRef.current?.open();
});
Enter fullscreen mode Exit fullscreen mode

};

when i am opening cancelModal focus is not setting correctly
if we use multiple flushSync inside same method. Does it work as expected

Collapse
 
jcubic profile image
Jakub T. Jankiewicz

The demo scroll Dev.to post page when click Add Task. It's worth fixing this issue.
Good article anyway.

Collapse
 
somshekhar profile image
Som Shekhar Mukherjee • Edited

Yeah I've noticed that too, but I don't know how to fix it 😅. Let me know if you have any solution to it.

Collapse
 
jcubic profile image
Jakub T. Jankiewicz • Edited

I have no idea, but from my experience if the page is iframe the only way for outer page to know what the iframe is doing is listen to post messages that are send by the codesandbox, but that's just a guess, maybe looking at forem source code will give you a clue what the page is doing. I would check if the same works with CodePen or something similar that is inside iframe.

Thread Thread
 
somshekhar profile image
Som Shekhar Mukherjee

I found why this is happening, it's because of scrollIntoView. It's scrolls the outer page as well to bring the lastTodo into view.

Swapping it with listRef.current.scrollTop = listRef.current.scrollHeight solves this. So, I guess its better to use the latter.

Collapse
 
devchester profile image
Chester Arellano

nice!

Collapse
 
devchester profile image
Chester Arellano

just keep posting with Sandbox example for readers' playground. keep it up! :D