Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warning: flushSync was called from inside a lifecycle method. #458

Open
catamphetamine opened this issue Jun 5, 2023 · 3 comments
Open

Comments

@catamphetamine
Copy link

I get the following warning in the console:

Warning: flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task.

The warning seems to originate from this flushSync() call:

ReactDOM.flushSync(() => {

The same issue was encountered in Mantine React component library. They've decided to migrate from react-popper to fix that in that issue.

@denisinvader
Copy link

Using Promise.resolve().then(popper.forceUpdate) instead of popper.forceUpdate() solves the issue as mentioned in salute-developers/plasma PR

@catamphetamine
Copy link
Author

So looks like the rationale for the suggested workaround is that react-popper's forceUpdate() function, calls flushSync() inside. Therefore, it shouldn't be called in a callback right after the component has re-rendered because that results in a second render right after the first one, and React doesn't like that, presumably for performance reasons. Spacing out those two renders in time via Promise.resolve() seems to fix the React warning.

@catamphetamine
Copy link
Author

catamphetamine commented Oct 21, 2023

I've tested the suggested Promise.resolve() approach and it doesn't really work and the warning is still being shown. What worked though is setTimeout(forceUpdate, 0). Not forget that the timeout should be "cleared" on component unmount.

const { styles, attributes, forceUpdate } = usePopper(...)
	
const updateTooltipPositionTimer = useRef()

// Update tooltip position.
if (updateTooltipPositionTimer.current) {
	clearTimeout(updateTooltipPositionTimer.current)
	updateTooltipPositionTimer.current = undefined
}
updateTooltipPositionTimer.current = setTimeout(() => {
	updateTooltipPositionTimer.current = undefined
	forceUpdate()
}, 0)

...

useEffect(() => {
	return () => {
		if (updateTooltipPositionTimer.current) {
			clearTimeout(updateTooltipPositionTimer.current)
			updateTooltipPositionTimer.current = undefined
		}
	}
}, [])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants